diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml new file mode 100644 index 000000000000..405a2b306592 --- /dev/null +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -0,0 +1,10 @@ +name: "Validate Gradle Wrapper" +on: [push, pull_request] + +jobs: + validation: + name: "Validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: gradle/wrapper-validation-action@v1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0f58be1e0ff..2295a0928826 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,8 +7,8 @@ First off, thank you for taking the time to contribute! :+1: :tada: * [Code of Conduct](#code-of-conduct) * [How to Contribute](#how-to-contribute) * [Discuss](#discuss) - * [Create a Ticket](#create-a-ticket) - * [Ticket Lifecycle](#ticket-lifecycle) + * [Create an Issue](#create-an-issue) + * [Issue Lifecycle](#issue-lifecycle) * [Submit a Pull Request](#submit-a-pull-request) * [Build from Source](#build-from-source) * [Source Code Style](#source-code-style) @@ -24,70 +24,71 @@ Please report unacceptable behavior to spring-code-of-conduct@pivotal.io. #### Discuss -If you have a question, check StackOverflow using -[this list of tags](https://spring.io/questions), organized by Spring project. -Find an existing discussion or start a new one if necessary. +If you have a question, check Stack Overflow using +[this list of tags](https://stackoverflow.com/questions/tagged/spring+or+spring-mvc+or+spring-aop+or+spring-jdbc+or+spring-transactions+or+spring-annotations+or+spring-jms+or+spring-el+or+spring-test+or+spring+or+spring-remoting+or+spring-orm+or+spring-jmx+or+spring-cache+or+spring-webflux?tab=Newest). +Find an existing discussion, or start a new one if necessary. -If you suspect an issue, perform a search in the -[GitHub issue tracker](https://github.com/spring-projects/spring-framework/issues), using a few different keywords. -When you find related issues and discussions, prior or current, it helps you to learn and -it helps us to make a decision. +If you believe there is an issue, search through +[existing issues](https://github.com/spring-projects/spring-framework/issues) trying a +few different ways to find discussions, past or current, that are related to the issue. +Reading those discussions helps you to learn about the issue, and helps us to make a +decision. -#### Create a Ticket -Reporting an issue or making a feature request is a great way to contribute. Your feedback -and the conversations that result from it provide a continuous flow of ideas. +#### Create an Issue -Before you create a ticket, please take the time to [research first](#discuss). +Reporting an issue or making a feature request is a great way to contribute. Your feedback +and the conversations that result from it provide a continuous flow of ideas. However, +before creating a ticket, please take the time to [discuss and research](#discuss) first. -If creating a ticket after a discussion on StackOverflow, please provide a self-sufficient description in the ticket, independent of the details on StackOverflow. We understand this is extra work but the issue tracker is an important place of record for design discussions and decisions that can often be referenced long after the fix version, for example to revisit decisions, to understand the origin of a feature, and so on. +If creating an issue after a discussion on Stack Overflow, please provide a description +in the issue instead of simply referring to Stack Overflow. The issue tracker is an +important place of record for design discussions and should be self-sufficient. -When ready create a ticket in the [GitHub issue tracker](https://github.com/spring-projects/spring-framework/issues). +Once you're ready, create an issue on +[GitHub](https://github.com/spring-projects/spring-framework/issues). -#### Ticket Lifecycle +#### Issue Lifecycle When an issue is first created, it is flagged `waiting-for-triage` waiting for a team -member to triage it. Within a day or two, the issue will then be reviewed and the team -may ask for further information if needed. Based on the findings, the issue is either -assigned a fix version or declined. +member to triage it. Once the issue has been reviewed, the team may ask for further +information if needed, and based on the findings, the issue is either assigned a target +milestone or is closed with a specific status. -When a fix is ready, the issue is closed and may still be re-opened. Once a fix is -released, the issue can't be reopened. If necessary, you will need to create a new, -related ticket with a fresh description. +When a fix is ready, the issue is closed and may still be re-opened until the fix is +released. After that the issue will typically no longer be reopened. In rare cases if the +issue was not at all fixed, the issue may be re-opened. In most cases however any +follow-up reports will need to be created as new issues with a fresh description. #### Submit a Pull Request -You can contribute a source code change by submitting a pull request. - 1. If you have not previously done so, please sign the -[Contributor License Agreement](https://cla.pivotal.io/sign/spring). You will also be reminded -automatically when you submit a pull request. +[Contributor License Agreement](https://cla.pivotal.io/sign/spring). You will be reminded +automatically when you submit the PR. -1. Should you create a ticket first? The answer is no. Just create the pull request and use -the description to provide context and motivation, as you would for an issue. If you want -to start a discussion first or have already created an issue, once a pull request is created, -we will close the issue as superseded by the pull request, and the discussion of the issue -will continue under the pull request. +1. Should you create an issue first? No, just create the pull request and use the +description to provide context and motivation, as you would for an issue. If you want +to start a discussion first or have already created an issue, once a pull request is +created, we will close the issue as superseded by the pull request, and the discussion +about the issue will continue under the pull request. 1. Always check out the `master` branch and submit pull requests against it (for target version see [settings.gradle](settings.gradle)). Backports to prior versions will be considered on a case-by-case basis and reflected as the fix version in the issue tracker. -1. Use short branch names, preferably based on the GitHub issue (e.g. `22276`), or -otherwise using succinct, lower-case, dash (-) delimited names, such as `fix-warnings`. - 1. Choose the granularity of your commits consciously and squash commits that represent multiple edits or corrections of the same logical change. See [Rewriting History section of Pro Git](https://git-scm.com/book/en/Git-Tools-Rewriting-History) -for an overview of streamlining commit history. +for an overview of streamlining the commit history. 1. Format commit messages using 55 characters for the subject line, 72 characters per line for the description, followed by the issue fixed, e.g. `Closes gh-22276`. See the [Commit Guidelines section of Pro Git](https://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project#Commit-Guidelines) -for best practices around commit messages and use `git log` to see some examples. +for best practices around commit messages, and use `git log` to see some examples. -1. List the GitHub issue number in the PR description. +1. If there is a prior issue, reference the GitHub issue number in the description of the +pull request. If accepted, your contribution may be heavily modified as needed prior to merging. You will likely retain author attribution for your Git commits granted that the bulk of @@ -115,15 +116,15 @@ source code into your IDE. The wiki pages [Code Style](https://github.com/spring-projects/spring-framework/wiki/Code-Style) and [IntelliJ IDEA Editor Settings](https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings) -defines the source file coding standards we use along with some IDEA editor settings we customize. +define the source file coding standards we use along with some IDEA editor settings we customize. ### Reference Docs -The reference documentation is in the [src/docs/asciidoc](src/docs/asciidoc) directory and, in +The reference documentation is in the [src/docs/asciidoc](src/docs/asciidoc) directory, in [Asciidoctor](https://asciidoctor.org/) format. For trivial changes, you may be able to browse, edit source files, and submit directly from GitHub. -When making changes locally, use `./gradlew asciidoctor` and then browse the result under +When making changes locally, execute `./gradlew asciidoctor` and then browse the result under `build/asciidoc/html5/index.html`. Asciidoctor also supports live editing. For more details read diff --git a/README.md b/README.md index 737a4b6d3ba2..53a82b78e8b1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Spring Framework [![Build Status](https://build.spring.io/plugins/servlet/wittified/build-status/SPR-PUBM)](https://build.spring.io/browse/SPR) +# Spring Framework [![Build Status](https://ci.spring.io/api/v1/teams/spring-framework/pipelines/spring-framework-5.2.x/jobs/build/badge)](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.2.x?groups=Build") -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 is often referred to simply as "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". Spring provides everything required beyond the Java programming language for creating enterprise applications for a wide range of scenarios and architectures. Please read the [Overview](https://docs.spring.io/spring/docs/current/spring-framework-reference/overview.html#spring-introduction) section as reference for a more complete introduction. diff --git a/SECURITY.md b/SECURITY.md index 8ed0ff412377..038a36b56539 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,4 +8,4 @@ wiki page. ## Reporting a Vulnerability -Please see https://pivotal.io/security. +Please see https://spring.io/security-policy. diff --git a/build.gradle b/build.gradle index 3b28c31172c1..524e93f0a66d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,35 +1,18 @@ -buildscript { - dependencies { - classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.16' - classpath 'io.spring.asciidoctor:spring-asciidoctor-extensions:0.1.3.RELEASE' - } -} - plugins { - id 'io.spring.dependency-management' version '1.0.8.RELEASE' apply false - id 'org.jetbrains.kotlin.jvm' version '1.3.50' apply false - id 'org.jetbrains.dokka' version '0.9.18' apply false - id 'org.asciidoctor.convert' version '1.5.8' - id 'io.spring.nohttp' version '0.0.3.RELEASE' - id 'de.undercouch.download' version '4.0.0' - id 'com.gradle.build-scan' version '2.4.2' - id "com.jfrog.artifactory" version '4.9.8' apply false - id "io.freefair.aspectj" version "4.1.1" apply false - id "com.github.ben-manes.versions" version "0.24.0" -} - -if (System.getenv('GRADLE_ENTERPRISE_URL')) { - apply from: "$rootDir/gradle/build-scan-user-data.gradle" - buildScan { - captureTaskInputFiles = true - obfuscation { - ipAddresses { addresses -> addresses.collect { address -> '0.0.0.0'} } - } - publishAlways() - server = System.getenv('GRADLE_ENTERPRISE_URL') - } + id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false + id 'io.spring.ge.conventions' version '0.0.7' + id 'io.spring.nohttp' version '0.0.5.RELEASE' + id "io.freefair.aspectj" version '4.1.6' apply false + id 'org.jetbrains.dokka' version '0.10.1' apply false + id 'org.jetbrains.kotlin.jvm' version '1.3.72' apply false + id 'org.asciidoctor.jvm.convert' version '2.4.0' + id 'org.asciidoctor.jvm.pdf' version '2.4.0' + id "com.github.ben-manes.versions" version '0.28.0' + id 'com.gradle.build-scan' version '3.2' + id 'de.undercouch.download' version '4.1.1' } +apply from: "$rootDir/gradle/build-scan-user-data.gradle" ext { moduleProjects = subprojects.findAll { it.name.startsWith("spring-") } javaProjects = subprojects - project(":framework-bom") @@ -43,32 +26,31 @@ configure(allprojects) { project -> dependencyManagement { imports { - mavenBom "com.fasterxml.jackson:jackson-bom:2.10.0" - mavenBom "io.netty:netty-bom:4.1.43.Final" - mavenBom "io.projectreactor:reactor-bom:Dysprosium-SR1" - mavenBom "io.rsocket:rsocket-bom:1.0.0-RC5" - mavenBom "org.eclipse.jetty:jetty-bom:9.4.21.v20190926" - mavenBom "org.jetbrains.kotlin:kotlin-bom:1.3.50" - mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.3.2" - mavenBom "org.junit:junit-bom:5.5.2" + mavenBom "com.fasterxml.jackson:jackson-bom:2.10.5" + mavenBom "io.netty:netty-bom:4.1.51.Final" + mavenBom "io.projectreactor:reactor-bom:Dysprosium-SR25" + mavenBom "io.rsocket:rsocket-bom:1.0.4" + mavenBom "org.eclipse.jetty:jetty-bom:9.4.31.v20200723" + mavenBom "org.jetbrains.kotlin:kotlin-bom:1.3.72" + mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.3.5" + mavenBom "org.junit:junit-bom:5.6.3" } dependencies { - dependencySet(group: 'org.apache.logging.log4j', version: '2.12.1') { + dependencySet(group: 'org.apache.logging.log4j', version: '2.17.1') { entry 'log4j-api' entry 'log4j-core' - entry 'log4j-slf4j-impl' entry 'log4j-jul' + entry 'log4j-slf4j-impl' } - dependency "org.slf4j:slf4j-api:1.7.28" - + dependency "org.slf4j:slf4j-api:1.7.32" dependency "com.google.code.findbugs:jsr305:3.0.2" - dependencySet(group: 'org.aspectj', version: '1.9.4') { + dependencySet(group: 'org.aspectj', version: '1.9.7') { entry 'aspectjrt' entry 'aspectjtools' entry 'aspectjweaver' } - dependencySet(group: 'org.codehaus.groovy', version: '2.5.8') { + dependencySet(group: 'org.codehaus.groovy', version: '2.5.15') { entry 'groovy' entry 'groovy-jsr223' entry 'groovy-templates' @@ -78,37 +60,38 @@ configure(allprojects) { project -> dependency "io.reactivex:rxjava:1.3.8" dependency "io.reactivex:rxjava-reactive-streams:1.2.1" - dependency "io.reactivex.rxjava2:rxjava:2.2.13" + dependency "io.reactivex.rxjava2:rxjava:2.2.21" + dependency "io.projectreactor.tools:blockhound:1.0.6.RELEASE" - dependency "com.caucho:hessian:4.0.62" + dependency "com.caucho:hessian:4.0.63" dependency "com.fasterxml:aalto-xml:1.2.2" - dependency("com.fasterxml.woodstox:woodstox-core:5.2.0") { + dependency("com.fasterxml.woodstox:woodstox-core:6.2.3") { exclude group: "stax", name: "stax-api" } dependency "com.google.code.gson:gson:2.8.6" - dependency "com.google.protobuf:protobuf-java-util:3.10.0" + dependency "com.google.protobuf:protobuf-java-util:3.11.4" dependency "com.googlecode.protobuf-java-format:protobuf-java-format:1.4" dependency("com.thoughtworks.xstream:xstream:1.4.11.1") { exclude group: "xpp3", name: "xpp3_min" exclude group: "xmlpull", name: "xmlpull" } - dependency "org.apache.johnzon:johnzon-jsonb:1.2.1" + dependency "org.apache.johnzon:johnzon-jsonb:1.2.10" dependency("org.codehaus.jettison:jettison:1.3.8") { exclude group: "stax", name: "stax-api" } - dependencySet(group: 'org.jibx', version: '1.3.1') { + dependencySet(group: 'org.jibx', version: '1.3.3') { entry 'jibx-bind' entry 'jibx-run' } dependency "org.ogce:xpp3:1.1.6" - dependency "org.yaml:snakeyaml:1.25" + dependency "org.yaml:snakeyaml:1.27" dependency "com.h2database:h2:1.4.200" - dependency "com.github.ben-manes.caffeine:caffeine:2.8.0" - dependency "com.github.librepdf:openpdf:1.3.11" + dependency "com.github.ben-manes.caffeine:caffeine:2.8.8" + dependency "com.github.librepdf:openpdf:1.3.25" dependency "com.rometools:rome:1.12.2" dependency "commons-io:commons-io:2.5" - dependency "io.vavr:vavr:0.10.0" + dependency "io.vavr:vavr:0.10.3" dependency "net.sf.jopt-simple:jopt-simple:5.0.4" dependencySet(group: 'org.apache.activemq', version: '5.8.0') { entry 'activemq-broker' @@ -118,37 +101,37 @@ configure(allprojects) { project -> entry 'activemq-stomp' } dependency "org.apache.bcel:bcel:6.0" - dependency "org.apache.commons:commons-pool2:2.6.0" + dependency "org.apache.commons:commons-pool2:2.8.1" dependencySet(group: 'org.apache.derby', version: '10.14.2.0') { entry 'derby' entry 'derbyclient' } - dependency "org.apache.poi:poi-ooxml:4.1.1" - dependency "org.beanshell:bsh:2.0b5" - dependency "org.freemarker:freemarker:2.3.29" - dependency "org.hsqldb:hsqldb:2.5.0" + dependency "org.apache.poi:poi-ooxml:4.1.2" + dependency "org.apache-extras.beanshell:bsh:2.0b6" + dependency "org.freemarker:freemarker:2.3.30" + dependency "org.hsqldb:hsqldb:2.5.1" dependency "org.quartz-scheduler:quartz:2.3.2" dependency "org.codehaus.fabric3.api:commonj:1.1.0" dependency "net.sf.ehcache:ehcache:2.10.6" dependency "org.ehcache:jcache:1.0.1" dependency "org.ehcache:ehcache:3.4.0" - dependency "org.hibernate:hibernate-core:5.4.8.Final" - dependency "org.hibernate:hibernate-validator:6.0.17.Final" - dependency "org.webjars:webjars-locator-core:0.42" + dependency "org.hibernate:hibernate-core:5.4.28.Final" + dependency "org.hibernate:hibernate-validator:6.1.7.Final" + dependency "org.webjars:webjars-locator-core:0.46" dependency "org.webjars:underscorejs:1.8.3" - dependencySet(group: 'org.apache.tomcat', version: '9.0.27') { + dependencySet(group: 'org.apache.tomcat', version: '9.0.37') { entry 'tomcat-util' entry('tomcat-websocket') { exclude group: "org.apache.tomcat", name: "tomcat-websocket-api" exclude group: "org.apache.tomcat", name: "tomcat-servlet-api" } } - dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.27') { + dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.37') { entry 'tomcat-embed-core' entry 'tomcat-embed-websocket' } - dependencySet(group: 'io.undertow', version: '2.0.27.Final') { + dependencySet(group: 'io.undertow', version: '2.0.32.Final') { entry 'undertow-core' entry('undertow-websockets-jsr') { exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec" @@ -159,21 +142,21 @@ configure(allprojects) { project -> } } - dependencySet(group: 'com.squareup.okhttp3', version: '3.14.3') { + dependencySet(group: 'com.squareup.okhttp3', version: '3.14.9') { entry 'okhttp' entry 'mockwebserver' } - dependency("org.apache.httpcomponents:httpclient:4.5.10") { + dependency("org.apache.httpcomponents:httpclient:4.5.13") { exclude group: "commons-logging", name: "commons-logging" } dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") { exclude group: "commons-logging", name: "commons-logging" } - dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.0.3" + dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.4" - dependency "org.jruby:jruby:9.2.7.0" + dependency "org.jruby:jruby:9.2.11.1" dependency "org.python:jython-standalone:2.7.1" - dependency "org.mozilla:rhino:1.7.10" + dependency "org.mozilla:rhino:1.7.11" dependency "commons-fileupload:commons-fileupload:1.4" dependency "org.synchronoss.cloud:nio-multipart-parser:1.1.0" @@ -195,26 +178,26 @@ configure(allprojects) { project -> } dependency "org.testng:testng:6.14.3" dependency "org.hamcrest:hamcrest:2.1" - dependency "org.awaitility:awaitility:3.1.3" - dependency "org.assertj:assertj-core:3.14.0" + dependency "org.awaitility:awaitility:3.1.6" + dependency "org.assertj:assertj-core:3.18.1" dependencySet(group: 'org.xmlunit', version: '2.6.2') { entry 'xmlunit-assertj' entry('xmlunit-matchers') { exclude group: "org.hamcrest", name: "hamcrest-core" } } - dependencySet(group: 'org.mockito', version: '3.1.0') { + dependencySet(group: 'org.mockito', version: '3.3.3') { entry('mockito-core') { exclude group: "org.hamcrest", name: "hamcrest-core" } entry 'mockito-junit-jupiter' } - dependency "io.mockk:mockk:1.9.3" + dependency "io.mockk:mockk:1.10.2" - dependency("net.sourceforge.htmlunit:htmlunit:2.36.0") { + dependency("net.sourceforge.htmlunit:htmlunit:2.43.0") { exclude group: "commons-logging", name: "commons-logging" } - dependency("org.seleniumhq.selenium:htmlunit-driver:2.36.0") { + dependency("org.seleniumhq.selenium:htmlunit-driver:2.43.1") { exclude group: "commons-logging", name: "commons-logging" } dependency("org.seleniumhq.selenium:selenium-java:3.141.59") { @@ -240,9 +223,9 @@ configure(allprojects) { project -> } dependency "com.ibm.websphere:uow:6.0.2.17" - dependency "com.jamonapi:jamon:2.81" - dependency "joda-time:joda-time:2.10.4" - dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.5" + dependency "com.jamonapi:jamon:2.82" + dependency "joda-time:joda-time:2.10.10" + dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.7" dependency "org.javamoney:moneta:1.3" dependency "com.sun.activation:javax.activation:1.2.0" @@ -310,8 +293,10 @@ configure([rootProject] + javaProjects) { project -> group = "org.springframework" apply plugin: "java" + apply plugin: "java-test-fixtures" apply plugin: "checkstyle" apply plugin: 'org.springframework.build.compile' + apply from: "${rootDir}/gradle/custom-java-home.gradle" apply from: "${rootDir}/gradle/ide.gradle" pluginManager.withPlugin("kotlin") { @@ -340,7 +325,7 @@ configure([rootProject] + javaProjects) { project -> } checkstyle { - toolVersion = "8.26" + toolVersion = "8.38" configDir = rootProject.file("src/checkstyle") } @@ -374,14 +359,14 @@ configure([rootProject] + javaProjects) { project -> "https://tiles.apache.org/tiles-request/apidocs/", "https://tiles.apache.org/framework/apidocs/", "https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/", - "https://www.ehcache.org/apidocs/2.10.4", + "https://www.ehcache.org/apidocs/2.10.4/", "https://www.quartz-scheduler.org/api/2.3.0/", "https://fasterxml.github.io/jackson-core/javadoc/2.10/", "https://fasterxml.github.io/jackson-databind/javadoc/2.10/", "https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/", "https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/", "https://junit.org/junit4/javadoc/4.12/", - "https://junit.org/junit5/docs/5.5.2/api/" + "https://junit.org/junit5/docs/5.6.3/api/" ] as String[] } @@ -401,7 +386,7 @@ configure(rootProject) { nohttp { source.exclude "**/test-output/**" - whitelistFile = project.file("src/nohttp/whitelist.lines") + allowlistFile = project.file("src/nohttp/allowlist.lines") def rootPath = file(rootDir).toPath() def projectDirs = allprojects.collect { it.projectDir } + "${rootDir}/buildSrc" projectDirs.forEach { dir -> @@ -414,10 +399,6 @@ configure(rootProject) { } } - dependencies { - asciidoctor("io.spring.asciidoctor:spring-asciidoctor-extensions:0.1.3.RELEASE") - } - publishing { publications { mavenJava(MavenPublication) { diff --git a/buildSrc/README.md b/buildSrc/README.md index 7c722a362730..f48339e6d61f 100644 --- a/buildSrc/README.md +++ b/buildSrc/README.md @@ -1,4 +1,4 @@ -# Spring Framework build +# Spring Framework Build This folder contains the custom plugins and conventions for the Spring Framework build. They are declared in the `build.gradle` file in this folder. @@ -7,8 +7,8 @@ They are declared in the `build.gradle` file in this folder. ### Compiler conventions -The `org.springframework.build.compile` applies the Java compiler conventions to the build. -By default, the build is compiling sources with the `1.8` source and target compatibility. +The `org.springframework.build.compile` plugin applies the Java compiler conventions to the build. +By default, the build compiles sources with Java `1.8` source and target compatibility. You can test a different source compatibility version on the CLI with a project property like: ``` @@ -25,17 +25,11 @@ but doesn't affect the classpath of dependent projects. This plugin does not provide a `provided` configuration, as the native `compileOnly` and `testCompileOnly` configurations are preferred. -## Test sources - -The `org.springframework.build.test-sources` updates `testCompile` dependencies to include -the test source sets of `project()` dependencies. This plugin is used in the Spring Framework build -to share test utilities and fixtures amongst modules. - ## API Diff This plugin uses the [Gradle JApiCmp](https://github.com/melix/japicmp-gradle-plugin) plugin to generate API Diff reports for each Spring Framework module. This plugin is applied once on the root -project and create tasks in each framework module. Unlike previous versions of this part of the build, +project and creates tasks in each framework module. Unlike previous versions of this part of the build, there is no need for checking out a specific tag. The plugin will fetch the JARs we want to compare the current working version with. You can generate the reports for all modules or a single module: @@ -44,4 +38,4 @@ current working version with. You can generate the reports for all modules or a ./gradlew :spring-core:apiDiff -PbaselineVersion=5.1.0.RELEASE ``` -The reports are located under `build/reports/api-diff/$OLDVERSION_to_$NEWVERSION/`. \ No newline at end of file +The reports are located under `build/reports/api-diff/$OLDVERSION_to_$NEWVERSION/`. diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 1aed5f6e78a2..03f629496a28 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { implementation "me.champeau.gradle:japicmp-gradle-plugin:0.2.8" - implementation "com.google.guava:guava:18.0" // required by japicmp-gradle-plugin + implementation "com.google.guava:guava:28.2-jre" // required by japicmp-gradle-plugin } gradlePlugin { @@ -26,9 +26,5 @@ gradlePlugin { id = "org.springframework.build.optional-dependencies" implementationClass = "org.springframework.build.optional.OptionalDependenciesPlugin" } - testSourcesPlugin { - id = "org.springframework.build.test-sources" - implementationClass = "org.springframework.build.testsources.TestSourcesPlugin" - } } } diff --git a/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java b/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java index 5cb9a70a37e5..db51666f74b5 100644 --- a/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java +++ b/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ * with a dedicated property on the CLI: {@code "./gradlew test -PjavaSourceVersion=11"}. * * @author Brian Clozel + * @author Sam Brannen */ public class CompilerConventionsPlugin implements Plugin { @@ -40,13 +41,13 @@ public class CompilerConventionsPlugin implements Plugin { * The project property that can be used to switch the Java source * compatibility version for building source and test classes. */ - public static String JAVA_SOURCE_VERSION_PROPERTY = "javaSourceVersion"; + public static final String JAVA_SOURCE_VERSION_PROPERTY = "javaSourceVersion"; - public static JavaVersion DEFAULT_COMPILER_VERSION = JavaVersion.VERSION_1_8; + public static final JavaVersion DEFAULT_COMPILER_VERSION = JavaVersion.VERSION_1_8; - private static List COMPILER_ARGS; + private static final List COMPILER_ARGS; - private static List TEST_COMPILER_ARGS; + private static final List TEST_COMPILER_ARGS; static { List commonCompilerArgs = Arrays.asList( @@ -72,7 +73,8 @@ public void apply(Project project) { } /** - * Applies the common Java compiler options for sources and test sources. + * Applies the common Java compiler options for main sources, test fixture sources, and + * test sources. * @param project the current project */ private void applyJavaCompileConventions(Project project) { @@ -87,16 +89,18 @@ private void applyJavaCompileConventions(Project project) { java.setTargetCompatibility(DEFAULT_COMPILER_VERSION); project.getTasks().withType(JavaCompile.class) - .matching(javaCompile -> javaCompile.getName().equals(JavaPlugin.COMPILE_JAVA_TASK_NAME)) + .matching(compileTask -> compileTask.getName().equals(JavaPlugin.COMPILE_JAVA_TASK_NAME)) .forEach(compileTask -> { compileTask.getOptions().setCompilerArgs(COMPILER_ARGS); compileTask.getOptions().setEncoding("UTF-8"); }); project.getTasks().withType(JavaCompile.class) - .matching(javaCompile -> javaCompile.getName().equals(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME)) + .matching(compileTask -> compileTask.getName().equals(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME) + || compileTask.getName().equals("compileTestFixturesJava")) .forEach(compileTask -> { compileTask.getOptions().setCompilerArgs(TEST_COMPILER_ARGS); compileTask.getOptions().setEncoding("UTF-8"); }); } -} \ No newline at end of file + +} diff --git a/buildSrc/src/main/java/org/springframework/build/testsources/TestSourcesPlugin.java b/buildSrc/src/main/java/org/springframework/build/testsources/TestSourcesPlugin.java deleted file mode 100644 index 68b97661902c..000000000000 --- a/buildSrc/src/main/java/org/springframework/build/testsources/TestSourcesPlugin.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.build.testsources; - -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.ProjectDependency; -import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.plugins.JavaPluginConvention; -import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.SourceSetOutput; - -import org.springframework.build.optional.OptionalDependenciesPlugin; - -/** - * {@link Plugin} that automatically updates testCompile dependencies to include - * the test source sets of {@code project()} dependencies. - * - *

This plugin is used in the Spring Framework build to share test utilities and fixtures - * between projects. - * - * @author Phillip Webb - * @author Brian Clozel - */ -public class TestSourcesPlugin implements Plugin { - - /** - * List of configurations this plugin should look for project dependencies in. - */ - @SuppressWarnings("deprecation") - private static final List CONFIGURATIONS = Arrays.asList( - JavaPlugin.COMPILE_CONFIGURATION_NAME, - JavaPlugin.API_CONFIGURATION_NAME, - JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, - OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME, - JavaPlugin.TEST_COMPILE_CONFIGURATION_NAME); - - @Override - public void apply(Project project) { - project.getPlugins().withType(JavaPlugin.class, (plugin) -> addTestSourcesToProject(project)); - } - - private void addTestSourcesToProject(Project project) { - project.afterEvaluate(currentProject -> { - Set projectDependencies = new LinkedHashSet<>(); - collectProjectDependencies(projectDependencies, project); - projectDependencies.forEach(dep -> addTestSourcesFromDependency(currentProject, dep)); - }); - } - - private void collectProjectDependencies(Set projectDependencies, Project project) { - for (String configurationName : CONFIGURATIONS) { - Configuration configuration = project.getConfigurations().findByName(configurationName); - if (configuration != null) { - configuration.getDependencies().forEach(dependency -> { - if (dependency instanceof ProjectDependency) { - ProjectDependency projectDependency = (ProjectDependency) dependency; - projectDependencies.add(projectDependency); - collectProjectDependencies(projectDependencies, projectDependency.getDependencyProject()); - } - }); - } - } - } - - private void addTestSourcesFromDependency(final Project currentProject, ProjectDependency dependency) { - Project dependencyProject = dependency.getDependencyProject(); - dependencyProject.getPlugins().withType(JavaPlugin.class, plugin -> { - final JavaPluginConvention javaPlugin = dependencyProject.getConvention() - .getPlugin(JavaPluginConvention.class); - SourceSetOutput test = javaPlugin.getSourceSets().findByName(SourceSet.TEST_SOURCE_SET_NAME).getOutput(); - currentProject.getDependencies().add(JavaPlugin.TEST_COMPILE_CONFIGURATION_NAME, test); - }); - } -} diff --git a/ci/README.adoc b/ci/README.adoc new file mode 100644 index 000000000000..f66fd74a82c8 --- /dev/null +++ b/ci/README.adoc @@ -0,0 +1,57 @@ +== Spring Framework Concourse pipeline + +The Spring Framework uses https://concourse-ci.org/[Concourse] for its CI build and other automated tasks. +The Spring team has a dedicated Concourse instance available at https://ci.spring.io with a build pipeline +for https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.2.x[Spring Framework 5.2.x]. + +=== Setting up your development environment + +If you're part of the Spring Framework project on GitHub, you can get access to CI management features. +First, you need to go to https://ci.spring.io and install the client CLI for your platform (see bottom right of the screen). + +You can then login with the instance using: + +[source] +---- +$ fly -t spring login -n spring-framework -c https://ci.spring.io +---- + +Once logged in, you should get something like: + +[source] +---- +$ fly ts +name url team expiry +spring https://ci.spring.io spring-framework Wed, 25 Mar 2020 17:45:26 UTC +---- + +=== Pipeline configuration and structure + +The build pipelines are described in `pipeline.yml` file. + +This file is listing Concourse resources, i.e. build inputs and outputs such as container images, artifact repositories, source repositories, notification services, etc. + +It also describes jobs (a job is a sequence of inputs, tasks and outputs); jobs are organized by groups. + +The `pipeline.yml` definition contains `((parameters))` which are loaded from the `parameters.yml` file or from our https://docs.cloudfoundry.org/credhub/[credhub instance]. + +You'll find in this folder the following resources: + +* `pipeline.yml` the build pipeline +* `parameters.yml` the build parameters used for the pipeline +* `images/` holds the container images definitions used in this pipeline +* `scripts/` holds the build scripts that ship within the CI container images +* `tasks` contains the task definitions used in the main `pipeline.yml` + +=== Updating the build pipeline + +Updating files on the repository is not enough to update the build pipeline, as changes need to be applied. + +The pipeline can be deployed using the following command: + +[source] +---- +$ fly -t spring set-pipeline -p spring-framework-5.2.x -c ci/pipeline.yml -l ci/parameters.yml +---- + +NOTE: This assumes that you have credhub integration configured with the appropriate secrets. diff --git a/ci/config/changelog-generator.yml b/ci/config/changelog-generator.yml new file mode 100644 index 000000000000..a029e25582e4 --- /dev/null +++ b/ci/config/changelog-generator.yml @@ -0,0 +1,17 @@ +changelog: + repository: spring-projects/spring-framework + sections: + - title: ":star: New Features" + labels: + - "type: enhancement" + - title: ":lady_beetle: Bug Fixes" + labels: + - "type: bug" + - "type: regression" + - title: ":notebook_with_decorative_cover: Documentation" + labels: + - "type: documentation" + - title: ":hammer: Dependency Upgrades" + sort: "title" + labels: + - "type: dependency-upgrade" diff --git a/ci/config/release-scripts.yml b/ci/config/release-scripts.yml new file mode 100644 index 000000000000..d31f8cba00dc --- /dev/null +++ b/ci/config/release-scripts.yml @@ -0,0 +1,10 @@ +logging: + level: + io.spring.concourse: DEBUG +spring: + main: + banner-mode: off +sonatype: + exclude: + - 'build-info\.json' + - '.*\.zip' diff --git a/ci/images/README.adoc b/ci/images/README.adoc new file mode 100644 index 000000000000..6da9addd9ca5 --- /dev/null +++ b/ci/images/README.adoc @@ -0,0 +1,21 @@ +== CI Images + +These images are used by CI to run the actual builds. + +To build the image locally run the following from this directory: + +---- +$ docker build --no-cache -f /Dockerfile . +---- + +For example + +---- +$ docker build --no-cache -f spring-framework-ci-image/Dockerfile . +---- + +To test run: + +---- +$ docker run -it --entrypoint /bin/bash +---- diff --git a/ci/images/ci-image-jdk11/Dockerfile b/ci/images/ci-image-jdk11/Dockerfile new file mode 100644 index 000000000000..253720dc2e21 --- /dev/null +++ b/ci/images/ci-image-jdk11/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:focal-20220302 + +ADD setup.sh /setup.sh +ADD get-jdk-url.sh /get-jdk-url.sh +RUN ./setup.sh java11 + +ENV JAVA_HOME /opt/openjdk +ENV PATH $JAVA_HOME/bin:$PATH diff --git a/ci/images/ci-image/Dockerfile b/ci/images/ci-image/Dockerfile new file mode 100644 index 000000000000..157d7f28b848 --- /dev/null +++ b/ci/images/ci-image/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:focal-20220302 + +ADD setup.sh /setup.sh +ADD get-jdk-url.sh /get-jdk-url.sh +RUN ./setup.sh java8 + +ENV JAVA_HOME /opt/openjdk +ENV PATH $JAVA_HOME/bin:$PATH diff --git a/ci/images/get-jdk-url.sh b/ci/images/get-jdk-url.sh new file mode 100755 index 000000000000..fca99d595e5c --- /dev/null +++ b/ci/images/get-jdk-url.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +case "$1" in + java8) + echo "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u322-b06/OpenJDK8U-jdk_x64_linux_hotspot_8u322b06.tar.gz" + ;; + java11) + echo "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.14.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.14.1_1.tar.gz" + ;; + *) + echo $"Unknown java version" + exit 1 +esac diff --git a/ci/images/setup.sh b/ci/images/setup.sh new file mode 100755 index 000000000000..82f777d89fd4 --- /dev/null +++ b/ci/images/setup.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -ex + +########################################################### +# UTILS +########################################################### + +export DEBIAN_FRONTEND=noninteractive +apt-get update +apt-get install --no-install-recommends -y tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig +ln -fs /usr/share/zoneinfo/UTC /etc/localtime +dpkg-reconfigure --frontend noninteractive tzdata +rm -rf /var/lib/apt/lists/* + +curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh > /opt/concourse-java.sh + +curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.3.2/concourse-release-scripts-0.3.2.jar + +########################################################### +# JAVA +########################################################### +JDK_URL=$( ./get-jdk-url.sh $1 ) + +mkdir -p /opt/openjdk +cd /opt/openjdk +curl -L ${JDK_URL} | tar zx --strip-components=1 +test -f /opt/openjdk/bin/java +test -f /opt/openjdk/bin/javac + +########################################################### +# GRADLE ENTERPRISE +########################################################### +cd / +mkdir ~/.gradle +echo 'systemProp.user.name=concourse' > ~/.gradle/gradle.properties diff --git a/ci/parameters.yml b/ci/parameters.yml new file mode 100644 index 000000000000..26579fc60280 --- /dev/null +++ b/ci/parameters.yml @@ -0,0 +1,13 @@ +email-server: "smtp.svc.pivotal.io" +email-from: "ci@spring.io" +email-to: ["spring-framework-dev@pivotal.io"] +github-repo: "https://github.com/spring-projects/spring-framework.git" +github-repo-name: "spring-projects/spring-framework" +docker-hub-organization: "springci" +artifactory-server: "https://repo.spring.io" +branch: "5.2.x" +milestone: "5.2.x" +build-name: "spring-framework" +pipeline-name: "spring-framework" +concourse-url: "https://ci.spring.io" +task-timeout: 1h00m diff --git a/ci/pipeline.yml b/ci/pipeline.yml new file mode 100644 index 000000000000..1f57b3d999b9 --- /dev/null +++ b/ci/pipeline.yml @@ -0,0 +1,391 @@ +anchors: + git-repo-resource-source: &git-repo-resource-source + uri: ((github-repo)) + username: ((github-username)) + password: ((github-ci-release-token)) + branch: ((branch)) + gradle-enterprise-task-params: &gradle-enterprise-task-params + GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key)) + GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username)) + GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password)) + sonatype-task-params: &sonatype-task-params + SONATYPE_USERNAME: ((sonatype-username)) + SONATYPE_PASSWORD: ((sonatype-password)) + SONATYPE_URL: ((sonatype-url)) + SONATYPE_STAGING_PROFILE_ID: ((sonatype-staging-profile-id)) + artifactory-task-params: &artifactory-task-params + ARTIFACTORY_SERVER: ((artifactory-server)) + ARTIFACTORY_USERNAME: ((artifactory-username)) + ARTIFACTORY_PASSWORD: ((artifactory-password)) + build-project-task-params: &build-project-task-params + privileged: true + timeout: ((task-timeout)) + params: + BRANCH: ((branch)) + <<: *gradle-enterprise-task-params + docker-resource-source: &docker-resource-source + username: ((docker-hub-username)) + password: ((docker-hub-password)) + tag: ((milestone)) + slack-fail-params: &slack-fail-params + text: > + :concourse-failed: + [$TEXT_FILE_CONTENT] + text_file: git-repo/build/build-scan-uri.txt + silent: true + icon_emoji: ":concourse:" + username: concourse-ci + changelog-task-params: &changelog-task-params + name: generated-changelog/tag + tag: generated-changelog/tag + body: generated-changelog/changelog.md + github-task-params: &github-task-params + GITHUB_USERNAME: ((github-username)) + GITHUB_TOKEN: ((github-ci-release-token)) + +resource_types: +- name: artifactory-resource + type: registry-image + source: + repository: springio/artifactory-resource + tag: 0.0.17 +- name: github-release + type: registry-image + source: + repository: concourse/github-release-resource + tag: 1.5.5 +- name: github-status-resource + type: registry-image + source: + repository: dpb587/github-status-resource + tag: master +- name: slack-notification + type: registry-image + source: + repository: cfcommunity/slack-notification-resource + tag: latest +resources: +- name: git-repo + type: git + icon: github + source: + <<: *git-repo-resource-source +- name: every-morning + type: time + icon: alarm + source: + start: 8:00 AM + stop: 9:00 AM + location: Europe/Vienna +- name: ci-images-git-repo + type: git + icon: github + source: + uri: ((github-repo)) + branch: ((branch)) + paths: ["ci/images/*"] +- name: ci-image + type: docker-image + icon: docker + source: + <<: *docker-resource-source + repository: ((docker-hub-organization))/spring-framework-ci +- name: ci-image-jdk11 + type: docker-image + icon: docker + source: + <<: *docker-resource-source + repository: ((docker-hub-organization))/spring-framework-ci-jdk11 +- name: artifactory-repo + type: artifactory-resource + icon: package-variant + source: + uri: ((artifactory-server)) + username: ((artifactory-username)) + password: ((artifactory-password)) + build_name: ((build-name)) +- name: repo-status-build + type: github-status-resource + icon: eye-check-outline + source: + repository: ((github-repo-name)) + access_token: ((github-ci-status-token)) + branch: ((branch)) + context: build +- name: repo-status-jdk11-build + type: github-status-resource + icon: eye-check-outline + source: + repository: ((github-repo-name)) + access_token: ((github-ci-status-token)) + branch: ((branch)) + context: jdk11-build +- name: slack-alert + type: slack-notification + icon: slack + source: + url: ((slack-webhook-url)) +- name: github-pre-release + type: github-release + icon: briefcase-download-outline + source: + owner: spring-projects + repository: spring-framework + access_token: ((github-ci-release-token)) + pre_release: true + release: false +- name: github-release + type: github-release + icon: briefcase-download + source: + owner: spring-projects + repository: spring-framework + access_token: ((github-ci-release-token)) + pre_release: false +jobs: +- name: build-ci-images + plan: + - get: ci-images-git-repo + trigger: true + - in_parallel: + - put: ci-image + params: + build: ci-images-git-repo/ci/images + dockerfile: ci-images-git-repo/ci/images/ci-image/Dockerfile + - put: ci-image-jdk11 + params: + build: ci-images-git-repo/ci/images + dockerfile: ci-images-git-repo/ci/images/ci-image-jdk11/Dockerfile +- name: build + serial: true + public: true + plan: + - get: ci-image + - get: git-repo + trigger: true + - put: repo-status-build + params: { state: "pending", commit: "git-repo" } + - do: + - task: build-project + image: ci-image + file: git-repo/ci/tasks/build-project.yml + <<: *build-project-task-params + on_failure: + do: + - put: repo-status-build + params: { state: "failure", commit: "git-repo" } + - put: slack-alert + params: + <<: *slack-fail-params + - put: repo-status-build + params: { state: "success", commit: "git-repo" } + - put: artifactory-repo + params: &artifactory-params + signing_key: ((signing-key)) + signing_passphrase: ((signing-passphrase)) + repo: libs-snapshot-local + folder: distribution-repository + build_uri: "https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}" + build_number: "${BUILD_PIPELINE_NAME}-${BUILD_JOB_NAME}-${BUILD_NAME}" + disable_checksum_uploads: true + threads: 8 + artifact_set: + - include: + - "/**/spring-*.zip" + properties: + "zip.name": "spring-framework" + "zip.displayname": "Spring Framework" + "zip.deployed": "false" + - include: + - "/**/spring-*-docs.zip" + properties: + "zip.type": "docs" + - include: + - "/**/spring-*-dist.zip" + properties: + "zip.type": "dist" + - include: + - "/**/spring-*-schema.zip" + properties: + "zip.type": "schema" + get_params: + threads: 8 +- name: jdk11-build + serial: true + public: true + plan: + - get: ci-image-jdk11 + - get: git-repo + - get: every-morning + trigger: true + - put: repo-status-jdk11-build + params: { state: "pending", commit: "git-repo" } + - do: + - task: check-project + image: ci-image-jdk11 + file: git-repo/ci/tasks/check-project.yml + <<: *build-project-task-params + on_failure: + do: + - put: repo-status-jdk11-build + params: { state: "failure", commit: "git-repo" } + - put: slack-alert + params: + <<: *slack-fail-params + - put: repo-status-jdk11-build + params: { state: "success", commit: "git-repo" } +- name: stage-milestone + serial: true + plan: + - get: ci-image + - get: git-repo + trigger: false + - task: stage + image: ci-image + file: git-repo/ci/tasks/stage-version.yml + params: + RELEASE_TYPE: M + <<: *gradle-enterprise-task-params + - put: artifactory-repo + params: + <<: *artifactory-params + repo: libs-staging-local + - put: git-repo + params: + repository: stage-git-repo +- name: promote-milestone + serial: true + plan: + - get: ci-image + - get: git-repo + trigger: false + - get: artifactory-repo + trigger: false + passed: [stage-milestone] + params: + download_artifacts: false + save_build_info: true + - task: promote + image: ci-image + file: git-repo/ci/tasks/promote-version.yml + params: + RELEASE_TYPE: M + <<: *artifactory-task-params + - task: generate-changelog + file: git-repo/ci/tasks/generate-changelog.yml + params: + RELEASE_TYPE: M + <<: *github-task-params + - put: github-pre-release + params: + <<: *changelog-task-params +- name: stage-rc + serial: true + plan: + - get: ci-image + - get: git-repo + trigger: false + - task: stage + image: ci-image + file: git-repo/ci/tasks/stage-version.yml + params: + RELEASE_TYPE: RC + <<: *gradle-enterprise-task-params + - put: artifactory-repo + params: + <<: *artifactory-params + repo: libs-staging-local + - put: git-repo + params: + repository: stage-git-repo +- name: promote-rc + serial: true + plan: + - get: ci-image + - get: git-repo + trigger: false + - get: artifactory-repo + trigger: false + passed: [stage-rc] + params: + download_artifacts: false + save_build_info: true + - task: promote + image: ci-image + file: git-repo/ci/tasks/promote-version.yml + params: + RELEASE_TYPE: RC + <<: *artifactory-task-params + - task: generate-changelog + file: git-repo/ci/tasks/generate-changelog.yml + params: + RELEASE_TYPE: RC + <<: *github-task-params + - put: github-pre-release + params: + <<: *changelog-task-params +- name: stage-release + serial: true + plan: + - get: ci-image + - get: git-repo + trigger: false + - task: stage + image: ci-image + file: git-repo/ci/tasks/stage-version.yml + params: + RELEASE_TYPE: RELEASE + <<: *gradle-enterprise-task-params + - put: artifactory-repo + params: + <<: *artifactory-params + repo: libs-staging-local + - put: git-repo + params: + repository: stage-git-repo +- name: promote-release + serial: true + plan: + - get: ci-image + - get: git-repo + trigger: false + - get: artifactory-repo + trigger: false + passed: [stage-release] + params: + download_artifacts: true + save_build_info: true + - task: promote + image: ci-image + file: git-repo/ci/tasks/promote-version.yml + params: + RELEASE_TYPE: RELEASE + <<: *artifactory-task-params + <<: *sonatype-task-params +- name: create-github-release + serial: true + plan: + - get: ci-image + - get: git-repo + - get: artifactory-repo + trigger: true + passed: [promote-release] + params: + download_artifacts: false + save_build_info: true + - task: generate-changelog + file: git-repo/ci/tasks/generate-changelog.yml + params: + RELEASE_TYPE: RELEASE + <<: *github-task-params + - put: github-release + params: + <<: *changelog-task-params + +groups: +- name: "builds" + jobs: ["build", "jdk11-build"] +- name: "releases" + jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"] +- name: "ci-images" + jobs: ["build-ci-images"] diff --git a/ci/scripts/build-project.sh b/ci/scripts/build-project.sh new file mode 100755 index 000000000000..3844d1a3ddb4 --- /dev/null +++ b/ci/scripts/build-project.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +source $(dirname $0)/common.sh +repository=$(pwd)/distribution-repository + +pushd git-repo > /dev/null +./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 -PdeploymentRepository=${repository} build publishAllPublicationsToDeploymentRepository +popd > /dev/null diff --git a/ci/scripts/check-project.sh b/ci/scripts/check-project.sh new file mode 100755 index 000000000000..94c4e8df65b4 --- /dev/null +++ b/ci/scripts/check-project.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +source $(dirname $0)/common.sh + +pushd git-repo > /dev/null +./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 check +popd > /dev/null diff --git a/ci/scripts/common.sh b/ci/scripts/common.sh new file mode 100644 index 000000000000..1accaa616732 --- /dev/null +++ b/ci/scripts/common.sh @@ -0,0 +1,2 @@ +source /opt/concourse-java.sh +setup_symlinks \ No newline at end of file diff --git a/ci/scripts/generate-changelog.sh b/ci/scripts/generate-changelog.sh new file mode 100755 index 000000000000..49e96c1ff326 --- /dev/null +++ b/ci/scripts/generate-changelog.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +CONFIG_DIR=git-repo/ci/config +version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) + +milestone=${version} +if [[ $RELEASE_TYPE = "RELEASE" ]]; then + milestone=${version%.RELEASE} +fi + +java -jar /github-changelog-generator.jar \ + --spring.config.location=${CONFIG_DIR}/changelog-generator.yml \ + ${milestone} generated-changelog/changelog.md + +echo ${version} > generated-changelog/version +echo v${version} > generated-changelog/tag diff --git a/ci/scripts/promote-version.sh b/ci/scripts/promote-version.sh new file mode 100755 index 000000000000..44c5ff626f91 --- /dev/null +++ b/ci/scripts/promote-version.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +source $(dirname $0)/common.sh +CONFIG_DIR=git-repo/ci/config + +version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) +export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json + +java -jar /opt/concourse-release-scripts.jar \ + --spring.config.location=${CONFIG_DIR}/release-scripts.yml \ + publishToCentral $RELEASE_TYPE $BUILD_INFO_LOCATION artifactory-repo || { exit 1; } + +java -jar /opt/concourse-release-scripts.jar \ + --spring.config.location=${CONFIG_DIR}/release-scripts.yml \ + promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; } + +echo "Promotion complete" +echo $version > version/version diff --git a/ci/scripts/stage-version.sh b/ci/scripts/stage-version.sh new file mode 100755 index 000000000000..5bb7300e799a --- /dev/null +++ b/ci/scripts/stage-version.sh @@ -0,0 +1,50 @@ +#!/bin/bash +set -e + +source $(dirname $0)/common.sh +repository=$(pwd)/distribution-repository + +pushd git-repo > /dev/null +git fetch --tags --all > /dev/null +popd > /dev/null + +git clone git-repo stage-git-repo > /dev/null + +pushd stage-git-repo > /dev/null + +snapshotVersion=$( awk -F '=' '$1 == "version" { print $2 }' gradle.properties ) +if [[ $RELEASE_TYPE = "M" ]]; then + stageVersion=$( get_next_milestone_release $snapshotVersion) + nextVersion=$snapshotVersion +elif [[ $RELEASE_TYPE = "RC" ]]; then + stageVersion=$( get_next_rc_release $snapshotVersion) + nextVersion=$snapshotVersion +elif [[ $RELEASE_TYPE = "RELEASE" ]]; then + stageVersion=$( get_next_release $snapshotVersion "RELEASE") + nextVersion=$( bump_version_number $snapshotVersion) +else + echo "Unknown release type $RELEASE_TYPE" >&2; exit 1; +fi + +echo "Staging $stageVersion (next version will be $nextVersion)" +sed -i "s/version=$snapshotVersion/version=$stageVersion/" gradle.properties + +git config user.name "Spring Builds" > /dev/null +git config user.email "spring-builds@users.noreply.github.com" > /dev/null +git add gradle.properties > /dev/null +git commit -m"Release v$stageVersion" > /dev/null +git tag -a "v$stageVersion" -m"Release v$stageVersion" > /dev/null + +./gradlew --no-daemon --max-workers=4 -PdeploymentRepository=${repository} build publishAllPublicationsToDeploymentRepository + +git reset --hard HEAD^ > /dev/null +if [[ $nextVersion != $snapshotVersion ]]; then + echo "Setting next development version (v$nextVersion)" + sed -i "s/version=$snapshotVersion/version=$nextVersion/" gradle.properties + git add gradle.properties > /dev/null + git commit -m"Next development version (v$nextVersion)" > /dev/null +fi; + +echo "Staging Complete" + +popd > /dev/null diff --git a/ci/scripts/sync-to-maven-central.sh b/ci/scripts/sync-to-maven-central.sh new file mode 100755 index 000000000000..b42631164ed5 --- /dev/null +++ b/ci/scripts/sync-to-maven-central.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json +version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) +java -jar /opt/concourse-release-scripts.jar syncToCentral "RELEASE" $BUILD_INFO_LOCATION || { exit 1; } + +echo "Sync complete" +echo $version > version/version diff --git a/ci/tasks/build-project.yml b/ci/tasks/build-project.yml new file mode 100644 index 000000000000..759749ef433f --- /dev/null +++ b/ci/tasks/build-project.yml @@ -0,0 +1,22 @@ +--- +platform: linux +inputs: +- name: git-repo +outputs: +- name: distribution-repository +- name: git-repo +caches: +- path: gradle +params: + BRANCH: + CI: true + GRADLE_ENTERPRISE_ACCESS_KEY: + GRADLE_ENTERPRISE_CACHE_USERNAME: + GRADLE_ENTERPRISE_CACHE_PASSWORD: + GRADLE_ENTERPRISE_URL: https://ge.spring.io +run: + path: bash + args: + - -ec + - | + ${PWD}/git-repo/ci/scripts/build-project.sh diff --git a/ci/tasks/check-project.yml b/ci/tasks/check-project.yml new file mode 100644 index 000000000000..ea6d6ddb94c8 --- /dev/null +++ b/ci/tasks/check-project.yml @@ -0,0 +1,22 @@ +--- +platform: linux +inputs: +- name: git-repo +outputs: +- name: distribution-repository +- name: git-repo +caches: +- path: gradle +params: + BRANCH: + CI: true + GRADLE_ENTERPRISE_ACCESS_KEY: + GRADLE_ENTERPRISE_CACHE_USERNAME: + GRADLE_ENTERPRISE_CACHE_PASSWORD: + GRADLE_ENTERPRISE_URL: https://ge.spring.io +run: + path: bash + args: + - -ec + - | + ${PWD}/git-repo/ci/scripts/check-project.sh diff --git a/ci/tasks/generate-changelog.yml b/ci/tasks/generate-changelog.yml new file mode 100755 index 000000000000..b3f40278c8e6 --- /dev/null +++ b/ci/tasks/generate-changelog.yml @@ -0,0 +1,20 @@ +--- +platform: linux +image_resource: + type: registry-image + source: + repository: springio/github-changelog-generator + tag: '0.0.7' +inputs: +- name: git-repo +- name: artifactory-repo +outputs: +- name: generated-changelog +params: + GITHUB_ORGANIZATION: + GITHUB_REPO: + GITHUB_USERNAME: + GITHUB_TOKEN: + RELEASE_TYPE: +run: + path: git-repo/ci/scripts/generate-changelog.sh diff --git a/ci/tasks/promote-version.yml b/ci/tasks/promote-version.yml new file mode 100644 index 000000000000..abdd8fed5c5c --- /dev/null +++ b/ci/tasks/promote-version.yml @@ -0,0 +1,18 @@ +--- +platform: linux +inputs: +- name: git-repo +- name: artifactory-repo +outputs: +- name: version +params: + RELEASE_TYPE: + ARTIFACTORY_SERVER: + ARTIFACTORY_USERNAME: + ARTIFACTORY_PASSWORD: + SONATYPE_USER: + SONATYPE_PASSWORD: + SONATYPE_URL: + SONATYPE_STAGING_PROFILE_ID: +run: + path: git-repo/ci/scripts/promote-version.sh diff --git a/ci/tasks/stage-version.yml b/ci/tasks/stage-version.yml new file mode 100644 index 000000000000..ded11483a76b --- /dev/null +++ b/ci/tasks/stage-version.yml @@ -0,0 +1,17 @@ +--- +platform: linux +inputs: +- name: git-repo +outputs: +- name: stage-git-repo +- name: distribution-repository +params: + RELEASE_TYPE: + CI: true + GRADLE_ENTERPRISE_CACHE_USERNAME: + GRADLE_ENTERPRISE_CACHE_PASSWORD: + GRADLE_ENTERPRISE_URL: https://ge.spring.io +caches: +- path: gradle +run: + path: git-repo/ci/scripts/stage-version.sh diff --git a/gradle.properties b/gradle.properties index 5fbb91d49b83..8673a6ed3fd2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=5.2.1.BUILD-SNAPSHOT +version=5.2.20.RELEASE org.gradle.jvmargs=-Xmx1536M org.gradle.caching=true org.gradle.parallel=true diff --git a/gradle/build-cache-settings.gradle b/gradle/build-cache-settings.gradle index d62ea57ebd26..5684b4942b8f 100644 --- a/gradle/build-cache-settings.gradle +++ b/gradle/build-cache-settings.gradle @@ -2,18 +2,16 @@ buildCache { local { enabled = true } - if (System.getenv('GRADLE_ENTERPRISE_URL')) { - remote(HttpBuildCache) { - enabled = true - url = "${System.getenv('GRADLE_ENTERPRISE_URL')}/cache/" - def cacheUsername = System.getenv('GRADLE_ENTERPRISE_CACHE_USERNAME') - def cachePassword = System.getenv('GRADLE_ENTERPRISE_CACHE_PASSWORD') - if (cacheUsername && cachePassword) { - push = true - credentials { - username = cacheUsername - password = cachePassword - } + remote(HttpBuildCache) { + enabled = true + url = 'https://ge.spring.io/cache/' + def cacheUsername = System.getenv('GRADLE_ENTERPRISE_CACHE_USERNAME') + def cachePassword = System.getenv('GRADLE_ENTERPRISE_CACHE_PASSWORD') + if (cacheUsername && cachePassword) { + push = true + credentials { + username = cacheUsername + password = cachePassword } } } diff --git a/gradle/build-scan-user-data.gradle b/gradle/build-scan-user-data.gradle index d4f483d66f26..156191d11526 100644 --- a/gradle/build-scan-user-data.gradle +++ b/gradle/build-scan-user-data.gradle @@ -1,90 +1,16 @@ -tagOs() -tagIde() -tagCiOrLocal() -addCiMetadata() -addGitMetadata() -addTestTaskMetadata() +addCustomJavaHomeMetadata() +addCustomJavaSourceVersionMetadata() -void tagOs() { - buildScan.tag System.getProperty('os.name') -} - -void tagIde() { - if (System.getProperty('idea.version')) { - buildScan.tag 'IntelliJ IDEA' - } else if (System.getProperty('eclipse.buildId')) { - buildScan.tag 'Eclipse' - } -} - -void tagCiOrLocal() { - buildScan.tag(isCi() ? 'CI' : 'LOCAL') -} - -void addGitMetadata() { - buildScan.background { - def gitCommitId = execAndGetStdout('git', 'rev-parse', '--short=8', '--verify', 'HEAD') - def gitBranchName = execAndGetStdout('git', 'rev-parse', '--abbrev-ref', 'HEAD') - def gitStatus = execAndGetStdout('git', 'status', '--porcelain') - - if(gitCommitId) { - def commitIdLabel = 'Git Commit ID' - value commitIdLabel, gitCommitId - link 'Git commit build scans', customValueSearchUrl([(commitIdLabel): gitCommitId]) - } - if (gitBranchName) { - tag gitBranchName - value 'Git branch', gitBranchName - } - if (gitStatus) { - tag 'dirty' - value 'Git status', gitStatus - } - } -} - -void addCiMetadata() { - def ciBuild = 'CI BUILD' - if (isBamboo()) { - buildScan.link ciBuild, System.getenv('bamboo_resultsUrl') +void addCustomJavaHomeMetadata() { + def customJavaHome = System.getProperty("customJavaHome") + if (customJavaHome) { + buildScan.value "Custom JAVA_HOME", customJavaHome } } -void addTestTaskMetadata() { - allprojects { - tasks.withType(Test) { test -> - doFirst { - buildScan.value "Test#maxParallelForks[${test.path}]", test.maxParallelForks.toString() - } - } +void addCustomJavaSourceVersionMetadata() { + def customJavaSourceVersion = System.getProperty("customJavaSourceVersion") + if (customJavaSourceVersion) { + buildScan.value "Custom Java Source Version", customJavaSourceVersion } } - -boolean isCi() { - isBamboo() -} - -boolean isBamboo() { - System.getenv('bamboo_resultsUrl') -} - -String execAndGetStdout(String... args) { - def stdout = new ByteArrayOutputStream() - exec { - commandLine(args) - standardOutput = stdout - } - return stdout.toString().trim() -} - -String customValueSearchUrl(Map search) { - def query = search.collect { name, value -> - "search.names=${encodeURL(name)}&search.values=${encodeURL(value)}" - }.join('&') - - "$buildScan.server/scans?$query" -} - -String encodeURL(String url) { - URLEncoder.encode(url, 'UTF-8') -} diff --git a/gradle/custom-java-home.gradle b/gradle/custom-java-home.gradle new file mode 100644 index 000000000000..54d1de1eb8f9 --- /dev/null +++ b/gradle/custom-java-home.gradle @@ -0,0 +1,80 @@ +// ----------------------------------------------------------------------------- +// +// This script adds support for the following two JVM system properties +// that control the build for alternative JDKs (i.e., a JDK other than +// the one used to launch the Gradle process). +// +// - customJavaHome: absolute path to the alternate JDK installation to +// use to compile Java code and execute tests. This system property +// is also used in spring-oxm.gradle to determine whether JiBX is +// supported. +// +// - customJavaSourceVersion: Java version supplied to the `--release` +// command line flag to control the Java source and target +// compatibility version. Supported versions include 9 or higher. +// Do not set this system property if Java 8 should be used. +// +// Examples: +// +// ./gradlew -DcustomJavaHome=/Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home test +// +// ./gradlew --no-build-cache -DcustomJavaHome=/Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home test +// +// ./gradlew -DcustomJavaHome=/Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home -DcustomJavaSourceVersion=14 test +// +// +// Credits: inspired by work from Marc Philipp and Stephane Nicoll +// +// ----------------------------------------------------------------------------- + +import org.gradle.internal.os.OperatingSystem +// import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile + +def customJavaHome = System.getProperty("customJavaHome") + +if (customJavaHome) { + def customJavaHomeDir = new File(customJavaHome) + def customJavaSourceVersion = System.getProperty("customJavaSourceVersion") + + tasks.withType(JavaCompile) { + logger.info("Java home for " + it.name + " task in " + project.name + ": " + customJavaHomeDir) + options.forkOptions.javaHome = customJavaHomeDir + inputs.property("customJavaHome", customJavaHome) + if (customJavaSourceVersion) { + options.compilerArgs += [ "--release", customJavaSourceVersion] + inputs.property("customJavaSourceVersion", customJavaSourceVersion) + } + } + + tasks.withType(GroovyCompile) { + logger.info("Java home for " + it.name + " task in " + project.name + ": " + customJavaHomeDir) + options.forkOptions.javaHome = customJavaHomeDir + inputs.property("customJavaHome", customJavaHome) + if (customJavaSourceVersion) { + options.compilerArgs += [ "--release", customJavaSourceVersion] + inputs.property("customJavaSourceVersion", customJavaSourceVersion) + } + } + + /* + tasks.withType(KotlinJvmCompile) { + logger.info("Java home for " + it.name + " task in " + project.name + ": " + customJavaHome) + kotlinOptions.jdkHome = customJavaHomeDir + inputs.property("customJavaHome", customJavaHome) + } + */ + + tasks.withType(Test) { + def javaExecutable = customJavaHome + "/bin/java" + if (OperatingSystem.current().isWindows()) { + javaExecutable += ".exe" + } + logger.info("Java executable for " + it.name + " task in " + project.name + ": " + javaExecutable) + executable = javaExecutable + inputs.property("customJavaHome", customJavaHome) + if (customJavaSourceVersion) { + inputs.property("customJavaSourceVersion", customJavaSourceVersion) + } + } + +} diff --git a/gradle/docs.gradle b/gradle/docs.gradle index 51b51252e860..27005827312d 100644 --- a/gradle/docs.gradle +++ b/gradle/docs.gradle @@ -1,3 +1,20 @@ +configurations { + asciidoctorExt +} + +dependencies { + asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.0.RELEASE") +} + +repositories { + maven { + url "https://repo.spring.io/release" + mavenContent { + includeGroup "io.spring.asciidoctor" + } + } +} + /** * Produce Javadoc for all Spring Framework modules in "build/docs/javadoc" */ @@ -48,39 +65,49 @@ dokka { dependsOn { tasks.getByName("api") } + doFirst { - classpath = moduleProjects.collect { project -> project.jar.outputs.files.getFiles() }.flatten() - classpath += files(moduleProjects.collect { it.sourceSets.main.compileClasspath }) - sourceDirs = files(moduleProjects - .findAll { - it.pluginManager.hasPlugin("kotlin") + configuration { + classpath = moduleProjects.collect { project -> project.jar.outputs.files.getFiles() }.flatten() + classpath += files(moduleProjects.collect { it.sourceSets.main.compileClasspath }) + + moduleProjects.findAll { + it.pluginManager.hasPlugin("kotlin") + }.each { project -> + def kotlinDirs = project.sourceSets.main.kotlin.srcDirs.collect() + kotlinDirs -= project.sourceSets.main.java.srcDirs + kotlinDirs.each { dir -> + if (dir.exists()) { + sourceRoot { + path = dir.path + } + } } - .collect { project -> - def kotlinDirs = project.sourceSets.main.kotlin.srcDirs.collect() - kotlinDirs -= project.sourceSets.main.java.srcDirs - }) + } + } } - moduleName = "spring-framework" + outputFormat = "html" outputDirectory = "$buildDir/docs/kdoc" - externalDocumentationLink { - url = new URL("https://docs.spring.io/spring-framework/docs/$version/javadoc-api/") - packageListUrl = new File(buildDir, "docs/javadoc/package-list").toURI().toURL() - } - externalDocumentationLink { - url = new URL("https://projectreactor.io/docs/core/release/api/") - } - externalDocumentationLink { - url = new URL("https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/") - } - externalDocumentationLink { - url = new URL("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/") + configuration { + moduleName = "spring-framework" + + externalDocumentationLink { + url = new URL("https://docs.spring.io/spring-framework/docs/$version/javadoc-api/") + packageListUrl = new File(buildDir, "docs/javadoc/package-list").toURI().toURL() + } + externalDocumentationLink { + url = new URL("https://projectreactor.io/docs/core/release/api/") + } + externalDocumentationLink { + url = new URL("https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/") + } } } task downloadResources(type: Download) { - def version = "0.1.3.RELEASE" + def version = "0.2.1.RELEASE" src "https://repo.spring.io/release/io/spring/docresources/" + "spring-doc-resources/$version/spring-doc-resources-${version}.zip" dest project.file("$buildDir/docs/spring-doc-resources.zip") @@ -93,27 +120,13 @@ task extractDocResources(type: Copy, dependsOn: downloadResources) { into "$buildDir/docs/spring-docs-resources/" } -/** - * Produce the Spring Framework Reference documentation - * from "src/docs/asciidoc" into "build/asciidoc/html5" - */ -asciidoctor { - sources { - include '*.adoc' - } - outputDir "$buildDir/docs/ref-docs/" - resources { - from(sourceDir) { - include 'images/*', 'css/**', 'js/**' +asciidoctorj { + modules { + pdf { + version '1.5.0-beta.8' } - from "$buildDir/docs/spring-docs-resources/" - } - logDocuments = true - backends = ["html5"] - // only ouput PDF documentation for non-SNAPSHOT builds - if (!project.getVersion().toString().contains("BUILD-SNAPSHOT")) { - backends += "pdf" } + fatalWarnings ".*" options doctype: 'book', eruby: 'erubis' attributes([ icons: 'font', @@ -125,19 +138,51 @@ asciidoctor { sectnums: '', 'source-highlighter': 'highlight.js', highlightjsdir: 'js/highlight', - 'highlightjs-theme': 'github', + 'highlightjs-theme': 'github', // 'googlecode', stylesdir: 'css/', stylesheet: 'stylesheet.css', 'spring-version': project.version ]) } -asciidoctor.dependsOn extractDocResources +/** + * Generate the Spring Framework Reference documentation from "src/docs/asciidoc" + * in "build/docs/ref-docs/html5". + */ +asciidoctor { + baseDirFollowsSourceDir() + configurations 'asciidoctorExt' + sources { + include '*.adoc' + } + outputDir "$buildDir/docs/ref-docs/html5" + logDocuments = true + resources { + from(sourceDir) { + include 'images/*', 'css/**', 'js/**' + } + from extractDocResources + } +} + +/** + * Generate the Spring Framework Reference documentation from "src/docs/asciidoc" + * in "build/docs/ref-docs/pdf". + */ +asciidoctorPdf { + baseDirFollowsSourceDir() + configurations 'asciidoctorExt' + sources { + include '*.adoc' + } + outputDir "$buildDir/docs/ref-docs/pdf" + logDocuments = true +} /** * Zip all docs (API and reference) into a single archive */ -task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'dokka']) { +task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'asciidoctorPdf', 'dokka']) { group = "Distribution" description = "Builds -${archiveClassifier} archive containing api and reference " + "for deployment at https://docs.spring.io/spring-framework/docs." @@ -150,10 +195,10 @@ task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'dokka']) { from (api) { into "javadoc-api" } - from ("$asciidoctor.outputDir/html5") { + from ("$asciidoctor.outputDir") { into "spring-framework-reference" } - from ("$asciidoctor.outputDir/pdf") { + from ("$asciidoctorPdf.outputDir") { into "spring-framework-reference/pdf" } from (dokka) { @@ -175,14 +220,14 @@ task schemaZip(type: Zip) { def Properties schemas = new Properties(); module.sourceSets.main.resources.find { - it.path.endsWith("META-INF/spring.schemas") + (it.path.endsWith("META-INF/spring.schemas") || it.path.endsWith("META-INF\\spring.schemas")) }?.withInputStream { schemas.load(it) } for (def key : schemas.keySet()) { def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1') assert shortName != key File xsdFile = module.sourceSets.main.resources.find { - it.path.endsWith(schemas.get(key)) + (it.path.endsWith(schemas.get(key)) || it.path.endsWith(schemas.get(key).replaceAll('\\/','\\\\'))) } assert xsdFile != null into (shortName) { diff --git a/gradle/ide.gradle b/gradle/ide.gradle index 554d4b3c5432..acb37abadbbf 100644 --- a/gradle/ide.gradle +++ b/gradle/ide.gradle @@ -29,12 +29,11 @@ eclipse.classpath.file.whenMerged { classpath -> classpath.entries.removeAll { entry -> (entry.path =~ /(?!.*?repack.*\.jar).*?\/([^\/]+)\/build\/libs\/[^\/]+\.jar/) } } - // Use separate main/test outputs (prevents WTP from packaging test classes) eclipse.classpath.defaultOutputDir = file(project.name+"/bin/eclipse") eclipse.classpath.file.beforeMerged { classpath -> classpath.entries.findAll{ it instanceof SourceFolder }.each { - if(it.output.startsWith("bin/")) { + if (it.output.startsWith("bin/")) { it.output = null } } diff --git a/gradle/publications.gradle b/gradle/publications.gradle index 97d6e51f05f6..86e0d2221c0b 100644 --- a/gradle/publications.gradle +++ b/gradle/publications.gradle @@ -1,5 +1,4 @@ apply plugin: "maven-publish" -apply plugin: 'com.jfrog.artifactory' publishing { publications { @@ -50,6 +49,16 @@ publishing { } } -artifactoryPublish { - publications(publishing.publications.mavenJava) +configureDeploymentRepository(project) + +void configureDeploymentRepository(Project project) { + project.plugins.withType(MavenPublishPlugin.class).all { + PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class); + if (project.hasProperty("deploymentRepository")) { + publishing.repositories.maven { + it.url = project.property("deploymentRepository") + it.name = "deployment" + } + } + } } \ No newline at end of file diff --git a/gradle/spring-module.gradle b/gradle/spring-module.gradle index c70263e18c0a..048735af1cbb 100644 --- a/gradle/spring-module.gradle +++ b/gradle/spring-module.gradle @@ -1,6 +1,5 @@ apply plugin: 'org.springframework.build.compile' apply plugin: 'org.springframework.build.optional-dependencies' -apply plugin: 'org.springframework.build.test-sources' apply from: "$rootDir/gradle/publications.gradle" jar { @@ -62,3 +61,11 @@ publishing { } } } + +// Disable publication of test fixture artifacts. +// +// Once we upgrade to Gradle 6.x, we will need to delete the following line ... +components.java.variants.removeAll { it.outgoingConfiguration.name.startsWith("testFixtures") } +// ... and uncomment the following two lines. +// components.java.withVariantsFromConfiguration(configurations.testFixturesApiElements) { skip() } +// components.java.withVariantsFromConfiguration(configurations.testFixturesRuntimeElements) { skip() } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f04d6a20aec6..5028f28f8e47 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/import-into-eclipse.md b/import-into-eclipse.md index d303e0c7412b..bb665d788a13 100644 --- a/import-into-eclipse.md +++ b/import-into-eclipse.md @@ -3,12 +3,12 @@ This document will guide you through the process of importing the Spring Framework projects into Eclipse or the Spring Tool Suite (_STS_). It is recommended that you have a recent version of Eclipse. As a bare minimum you will need Eclipse with full Java -8 support, the Kotlin plugin, and the Groovy plugin. +8 support, Eclipse Buildship, the Kotlin plugin, and the Groovy plugin. The following instructions have been tested against [STS](https://spring.io/tools) 4.3.2 ([download](https://github.com/spring-projects/sts4/wiki/Previous-Versions#spring-tools-432-changelog)) -with [Eclipse Buildship](https://projects.eclipse.org/projects/tools.buildship). The -instructions should work with the latest Eclipse distribution as long as you install +(based on Eclipse 4.12) with [Eclipse Buildship](https://projects.eclipse.org/projects/tools.buildship). +The instructions should work with the latest Eclipse distribution as long as you install [Buildship](https://marketplace.eclipse.org/content/buildship-gradle-integration). Note that STS 4 comes with Buildship preinstalled. @@ -23,7 +23,7 @@ _When instructed to execute `./gradlew` from the command line, be sure to execut 1. Switch to Groovy 2.5 (Preferences -> Groovy -> Compiler -> Switch to 2.5...) in Eclipse. 1. Change the _Forbidden reference (access rule)_ in Eclipse from Error to Warning (Preferences -> Java -> Compiler -> Errors/Warnings -> Deprecated and restricted API -> Forbidden reference (access rule)). -1. Optionally install the [AspectJ Development Tools](https://www.eclipse.org/ajdt/downloads/) (_AJDT_) if you need to work with the `spring-aspects` project. +1. Optionally install the [AspectJ Development Tools](https://marketplace.eclipse.org/content/aspectj-development-tools) (_AJDT_) if you need to work with the `spring-aspects` project. The AspectJ Development Tools available in the Eclipse Marketplace have been tested with these instructions using STS 4.5 (Eclipse 4.14). 1. Optionally install the [TestNG plugin](https://testng.org/doc/eclipse.html) in Eclipse if you need to execute TestNG tests in the `spring-test` module. 1. Build `spring-oxm` from the command line with `./gradlew :spring-oxm:check`. 1. To apply project specific settings, run `./gradlew eclipseBuildship` from the command line. diff --git a/integration-tests/integration-tests.gradle b/integration-tests/integration-tests.gradle index ab3bba7354b6..71e23b906049 100644 --- a/integration-tests/integration-tests.gradle +++ b/integration-tests/integration-tests.gradle @@ -1,12 +1,14 @@ description = "Spring Integration Tests" -apply plugin: "org.springframework.build.test-sources" - dependencies { testCompile(project(":spring-aop")) testCompile(project(":spring-beans")) testCompile(project(":spring-context")) testCompile(project(":spring-core")) + testCompile(testFixtures(project(":spring-aop"))) + testCompile(testFixtures(project(":spring-beans"))) + testCompile(testFixtures(project(":spring-core"))) + testCompile(testFixtures(project(":spring-tx"))) testCompile(project(":spring-expression")) testCompile(project(":spring-jdbc")) testCompile(project(":spring-orm")) diff --git a/integration-tests/src/test/java/.gitignore b/integration-tests/src/test/java/.gitignore deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/integration-tests/src/test/java/org/springframework/aop/config/AopNamespaceHandlerAdviceOrderIntegrationTests.java b/integration-tests/src/test/java/org/springframework/aop/config/AopNamespaceHandlerAdviceOrderIntegrationTests.java new file mode 100644 index 000000000000..da32ff120181 --- /dev/null +++ b/integration-tests/src/test/java/org/springframework/aop/config/AopNamespaceHandlerAdviceOrderIntegrationTests.java @@ -0,0 +1,119 @@ +/* + * Copyright 2002-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.aop.config; + +import java.util.ArrayList; +import java.util.List; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +/** + * Integration tests for advice invocation order for advice configured via the + * AOP namespace. + * + * @author Sam Brannen + * @since 5.2.7 + * @see org.springframework.aop.framework.autoproxy.AspectJAutoProxyAdviceOrderIntegrationTests + */ +class AopNamespaceHandlerAdviceOrderIntegrationTests { + + @Nested + @SpringJUnitConfig(locations = "AopNamespaceHandlerAdviceOrderIntegrationTests-afterFirst.xml") + @DirtiesContext + class AfterAdviceFirstTests { + + @Test + void afterAdviceIsInvokedFirst(@Autowired Echo echo, @Autowired InvocationTrackingAspect aspect) throws Exception { + assertThat(aspect.invocations).isEmpty(); + assertThat(echo.echo(42)).isEqualTo(42); + assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after returning"); + + aspect.invocations.clear(); + assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception())); + assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after throwing"); + } + } + + @Nested + @SpringJUnitConfig(locations = "AopNamespaceHandlerAdviceOrderIntegrationTests-afterLast.xml") + @DirtiesContext + class AfterAdviceLastTests { + + @Test + void afterAdviceIsInvokedLast(@Autowired Echo echo, @Autowired InvocationTrackingAspect aspect) throws Exception { + assertThat(aspect.invocations).isEmpty(); + assertThat(echo.echo(42)).isEqualTo(42); + assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after returning", "after"); + + aspect.invocations.clear(); + assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception())); + assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after throwing", "after"); + } + } + + + static class Echo { + + Object echo(Object obj) throws Exception { + if (obj instanceof Exception) { + throw (Exception) obj; + } + return obj; + } + } + + static class InvocationTrackingAspect { + + List invocations = new ArrayList<>(); + + Object around(ProceedingJoinPoint joinPoint) throws Throwable { + invocations.add("around - start"); + try { + return joinPoint.proceed(); + } + finally { + invocations.add("around - end"); + } + } + + void before() { + invocations.add("before"); + } + + void afterReturning() { + invocations.add("after returning"); + } + + void afterThrowing() { + invocations.add("after throwing"); + } + + void after() { + invocations.add("after"); + } + } + +} diff --git a/integration-tests/src/test/java/org/springframework/aop/config/AopNamespaceHandlerScopeIntegrationTests.java b/integration-tests/src/test/java/org/springframework/aop/config/AopNamespaceHandlerScopeIntegrationTests.java index 29f6e050812e..32ac556fe482 100644 --- a/integration-tests/src/test/java/org/springframework/aop/config/AopNamespaceHandlerScopeIntegrationTests.java +++ b/integration-tests/src/test/java/org/springframework/aop/config/AopNamespaceHandlerScopeIntegrationTests.java @@ -21,12 +21,12 @@ import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.core.testfixture.io.SerializationTestUtils; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpSession; import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.util.SerializationTestUtils; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; diff --git a/integration-tests/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorIntegrationTests.java b/integration-tests/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorIntegrationTests.java index e8d30cd33b96..cf067e01415c 100644 --- a/integration-tests/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorIntegrationTests.java +++ b/integration-tests/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorIntegrationTests.java @@ -26,17 +26,17 @@ import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; +import org.springframework.aop.testfixture.advice.CountingBeforeAdvice; +import org.springframework.aop.testfixture.advice.MethodCounter; +import org.springframework.aop.testfixture.interceptor.NopInterceptor; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.testfixture.beans.ITestBean; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.lang.Nullable; -import org.springframework.tests.aop.advice.CountingBeforeAdvice; -import org.springframework.tests.aop.advice.MethodCounter; -import org.springframework.tests.aop.interceptor.NopInterceptor; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.transaction.CallCountingTransactionManager; import org.springframework.transaction.NoTransactionException; import org.springframework.transaction.interceptor.TransactionInterceptor; +import org.springframework.transaction.testfixture.CallCountingTransactionManager; import static org.assertj.core.api.Assertions.assertThat; diff --git a/integration-tests/src/test/java/org/springframework/aop/framework/autoproxy/AspectJAutoProxyAdviceOrderIntegrationTests.java b/integration-tests/src/test/java/org/springframework/aop/framework/autoproxy/AspectJAutoProxyAdviceOrderIntegrationTests.java new file mode 100644 index 000000000000..78d45922be0c --- /dev/null +++ b/integration-tests/src/test/java/org/springframework/aop/framework/autoproxy/AspectJAutoProxyAdviceOrderIntegrationTests.java @@ -0,0 +1,233 @@ +/* + * Copyright 2002-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.aop.framework.autoproxy; + +import java.util.ArrayList; +import java.util.List; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +/** + * Integration tests for advice invocation order for advice configured via + * AspectJ auto-proxy support. + * + * @author Sam Brannen + * @since 5.2.7 + * @see org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests + */ +class AspectJAutoProxyAdviceOrderIntegrationTests { + + /** + * {@link After @After} advice declared as first after method in source code. + */ + @Nested + @SpringJUnitConfig(AfterAdviceFirstConfig.class) + @DirtiesContext + class AfterAdviceFirstTests { + + @Test + void afterAdviceIsInvokedLast(@Autowired Echo echo, @Autowired AfterAdviceFirstAspect aspect) throws Exception { + assertThat(aspect.invocations).isEmpty(); + assertThat(echo.echo(42)).isEqualTo(42); + assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end"); + + aspect.invocations.clear(); + assertThatExceptionOfType(Exception.class).isThrownBy( + () -> echo.echo(new Exception())); + assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end"); + } + } + + + /** + * This test class uses {@link AfterAdviceLastAspect} which declares its + * {@link After @After} advice as the last after advice type method + * in its source code. + * + *

On Java versions prior to JDK 7, we would have expected the {@code @After} + * advice method to be invoked before {@code @AfterThrowing} and + * {@code @AfterReturning} advice methods due to the AspectJ precedence + * rules implemented in + * {@link org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator}. + */ + @Nested + @SpringJUnitConfig(AfterAdviceLastConfig.class) + @DirtiesContext + class AfterAdviceLastTests { + + @Test + void afterAdviceIsInvokedLast(@Autowired Echo echo, @Autowired AfterAdviceLastAspect aspect) throws Exception { + assertThat(aspect.invocations).isEmpty(); + assertThat(echo.echo(42)).isEqualTo(42); + assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end"); + + aspect.invocations.clear(); + assertThatExceptionOfType(Exception.class).isThrownBy( + () -> echo.echo(new Exception())); + assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end"); + } + } + + + @Configuration + @EnableAspectJAutoProxy(proxyTargetClass = true) + static class AfterAdviceFirstConfig { + + @Bean + AfterAdviceFirstAspect echoAspect() { + return new AfterAdviceFirstAspect(); + } + + @Bean + Echo echo() { + return new Echo(); + } + } + + @Configuration + @EnableAspectJAutoProxy(proxyTargetClass = true) + static class AfterAdviceLastConfig { + + @Bean + AfterAdviceLastAspect echoAspect() { + return new AfterAdviceLastAspect(); + } + + @Bean + Echo echo() { + return new Echo(); + } + } + + static class Echo { + + Object echo(Object obj) throws Exception { + if (obj instanceof Exception) { + throw (Exception) obj; + } + return obj; + } + } + + /** + * {@link After @After} advice declared as first after method in source code. + */ + @Aspect + static class AfterAdviceFirstAspect { + + List invocations = new ArrayList<>(); + + @Pointcut("execution(* echo(*))") + void echo() { + } + + @After("echo()") + void after() { + invocations.add("after"); + } + + @AfterReturning("echo()") + void afterReturning() { + invocations.add("after returning"); + } + + @AfterThrowing("echo()") + void afterThrowing() { + invocations.add("after throwing"); + } + + @Before("echo()") + void before() { + invocations.add("before"); + } + + @Around("echo()") + Object around(ProceedingJoinPoint joinPoint) throws Throwable { + invocations.add("around - start"); + try { + return joinPoint.proceed(); + } + finally { + invocations.add("around - end"); + } + } + } + + /** + * {@link After @After} advice declared as last after method in source code. + */ + @Aspect + static class AfterAdviceLastAspect { + + List invocations = new ArrayList<>(); + + @Pointcut("execution(* echo(*))") + void echo() { + } + + @Around("echo()") + Object around(ProceedingJoinPoint joinPoint) throws Throwable { + invocations.add("around - start"); + try { + return joinPoint.proceed(); + } + finally { + invocations.add("around - end"); + } + } + + @Before("echo()") + void before() { + invocations.add("before"); + } + + @AfterReturning("echo()") + void afterReturning() { + invocations.add("after returning"); + } + + @AfterThrowing("echo()") + void afterThrowing() { + invocations.add("after throwing"); + } + + @After("echo()") + void after() { + invocations.add("after"); + } + } + +} diff --git a/integration-tests/src/test/java/org/springframework/scheduling/annotation/ScheduledAndTransactionalAnnotationIntegrationTests.java b/integration-tests/src/test/java/org/springframework/scheduling/annotation/ScheduledAndTransactionalAnnotationIntegrationTests.java index 95d897138f45..8b49193b8630 100644 --- a/integration-tests/src/test/java/org/springframework/scheduling/annotation/ScheduledAndTransactionalAnnotationIntegrationTests.java +++ b/integration-tests/src/test/java/org/springframework/scheduling/annotation/ScheduledAndTransactionalAnnotationIntegrationTests.java @@ -28,19 +28,19 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.testfixture.EnabledForTestGroups; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.stereotype.Repository; -import org.springframework.tests.EnabledForTestGroups; -import org.springframework.tests.transaction.CallCountingTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.testfixture.CallCountingTransactionManager; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.Mockito.mock; -import static org.springframework.tests.TestGroup.PERFORMANCE; +import static org.springframework.core.testfixture.TestGroup.PERFORMANCE; /** * Integration tests cornering bug SPR-8651, which revealed that @Scheduled methods may diff --git a/integration-tests/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementIntegrationTests.java b/integration-tests/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementIntegrationTests.java index 20dfe81d2f86..8ba437386b04 100644 --- a/integration-tests/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementIntegrationTests.java +++ b/integration-tests/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementIntegrationTests.java @@ -40,9 +40,9 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.stereotype.Repository; -import org.springframework.tests.transaction.CallCountingTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor; +import org.springframework.transaction.testfixture.CallCountingTransactionManager; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerAdviceOrderIntegrationTests-afterFirst.xml b/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerAdviceOrderIntegrationTests-afterFirst.xml new file mode 100644 index 000000000000..fd98a0c1b407 --- /dev/null +++ b/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerAdviceOrderIntegrationTests-afterFirst.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerAdviceOrderIntegrationTests-afterLast.xml b/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerAdviceOrderIntegrationTests-afterLast.xml new file mode 100644 index 000000000000..bcab0df678a4 --- /dev/null +++ b/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerAdviceOrderIntegrationTests-afterLast.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerScopeIntegrationTests-context.xml b/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerScopeIntegrationTests-context.xml index 56d265dc06fe..ab891535b514 100644 --- a/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerScopeIntegrationTests-context.xml +++ b/integration-tests/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerScopeIntegrationTests-context.xml @@ -11,19 +11,19 @@ - + - + - + - + diff --git a/integration-tests/src/test/resources/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorIntegrationTests-context.xml b/integration-tests/src/test/resources/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorIntegrationTests-context.xml index 7c2adb9e0120..90ea7dc1f663 100644 --- a/integration-tests/src/test/resources/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorIntegrationTests-context.xml +++ b/integration-tests/src/test/resources/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorIntegrationTests-context.xml @@ -34,7 +34,7 @@ - + @@ -74,20 +74,20 @@ - + - + - org.springframework.tests.sample.beans.ITestBean.getName + org.springframework.beans.testfixture.beans.ITestBean.getName - + - + 4 @@ -97,7 +97,7 @@ - + diff --git a/settings.gradle b/settings.gradle index 923271aace3c..cf24142b94e6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,15 +4,14 @@ pluginManagement { maven { url 'https://repo.spring.io/plugins-release' } } } - apply from: "$rootDir/gradle/build-cache-settings.gradle" include "spring-aop" include "spring-aspects" include "spring-beans" include "spring-context" -include "spring-context-support" include "spring-context-indexer" +include "spring-context-support" include "spring-core" include "kotlin-coroutines" project(':kotlin-coroutines').projectDir = file('spring-core/kotlin-coroutines') @@ -27,8 +26,8 @@ include "spring-oxm" include "spring-test" include "spring-tx" include "spring-web" -include "spring-webmvc" include "spring-webflux" +include "spring-webmvc" include "spring-websocket" include "framework-bom" include "integration-tests" diff --git a/spring-aop/spring-aop.gradle b/spring-aop/spring-aop.gradle index e4c20542e2cd..73bb378f39a7 100644 --- a/spring-aop/spring-aop.gradle +++ b/spring-aop/spring-aop.gradle @@ -6,4 +6,7 @@ dependencies { optional("org.aspectj:aspectjweaver") optional("org.apache.commons:commons-pool2") optional("com.jamonapi:jamon") + testCompile(testFixtures(project(":spring-beans"))) + testCompile(testFixtures(project(":spring-core"))) + testFixturesImplementation(testFixtures(project(":spring-core"))) } diff --git a/spring-aop/src/main/java/org/aopalliance/intercept/Joinpoint.java b/spring-aop/src/main/java/org/aopalliance/intercept/Joinpoint.java index 356087876396..5ede9b738c28 100644 --- a/spring-aop/src/main/java/org/aopalliance/intercept/Joinpoint.java +++ b/spring-aop/src/main/java/org/aopalliance/intercept/Joinpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ * terminology). * *

A runtime joinpoint is an event that occurs on a static - * joinpoint (i.e. a location in a the program). For instance, an + * joinpoint (i.e. a location in a program). For instance, an * invocation is the runtime joinpoint on a method (static joinpoint). * The static part of a given joinpoint can be generically retrieved * using the {@link #getStaticPart()} method. diff --git a/spring-aop/src/main/java/org/springframework/aop/AfterReturningAdvice.java b/spring-aop/src/main/java/org/springframework/aop/AfterReturningAdvice.java index b3b2c0a9d9bd..8c2c5d6ef8f0 100644 --- a/spring-aop/src/main/java/org/springframework/aop/AfterReturningAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/AfterReturningAdvice.java @@ -33,9 +33,9 @@ public interface AfterReturningAdvice extends AfterAdvice { /** * Callback after a given method successfully returned. * @param returnValue the value returned by the method, if any - * @param method method being invoked - * @param args arguments to the method - * @param target target of the method invocation. May be {@code null}. + * @param method the method being invoked + * @param args the arguments to the method + * @param target the target of the method invocation. May be {@code null}. * @throws Throwable if this object wishes to abort the call. * Any exception thrown will be returned to the caller if it's * allowed by the method signature. Otherwise the exception diff --git a/spring-aop/src/main/java/org/springframework/aop/DynamicIntroductionAdvice.java b/spring-aop/src/main/java/org/springframework/aop/DynamicIntroductionAdvice.java index 08c704857f75..2f46775b9459 100644 --- a/spring-aop/src/main/java/org/springframework/aop/DynamicIntroductionAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/DynamicIntroductionAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ *

Introductions are often mixins, enabling the building of composite * objects that can achieve many of the goals of multiple inheritance in Java. * - *

Compared to {qlink IntroductionInfo}, this interface allows an advice to + *

Compared to {@link IntroductionInfo}, this interface allows an advice to * implement a range of interfaces that is not necessarily known in advance. * Thus an {@link IntroductionAdvisor} can be used to specify which interfaces * will be exposed in an advised object. diff --git a/spring-aop/src/main/java/org/springframework/aop/MethodBeforeAdvice.java b/spring-aop/src/main/java/org/springframework/aop/MethodBeforeAdvice.java index ae791a21b04c..806744d09c31 100644 --- a/spring-aop/src/main/java/org/springframework/aop/MethodBeforeAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/MethodBeforeAdvice.java @@ -32,9 +32,9 @@ public interface MethodBeforeAdvice extends BeforeAdvice { /** * Callback before a given method is invoked. - * @param method method being invoked - * @param args arguments to the method - * @param target target of the method invocation. May be {@code null}. + * @param method the method being invoked + * @param args the arguments to the method + * @param target the target of the method invocation. May be {@code null}. * @throws Throwable if this object wishes to abort the call. * Any exception thrown will be returned to the caller if it's * allowed by the method signature. Otherwise the exception diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java index 1dacc08948b7..ec58afb29652 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -648,7 +648,7 @@ private PointcutBody getPointcutBody(String[] tokens, int startIndex) { } if (tokens[currentIndex].endsWith(")")) { - sb.append(tokens[currentIndex].substring(0, tokens[currentIndex].length() - 1)); + sb.append(tokens[currentIndex], 0, tokens[currentIndex].length() - 1); return new PointcutBody(numTokensConsumed, sb.toString().trim()); } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPoint.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPoint.java index 471647f89cf3..d1c4db25c284 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPoint.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -219,10 +219,12 @@ public Class[] getParameterTypes() { @Override @Nullable public String[] getParameterNames() { - if (this.parameterNames == null) { - this.parameterNames = parameterNameDiscoverer.getParameterNames(getMethod()); + String[] parameterNames = this.parameterNames; + if (parameterNames == null) { + parameterNames = parameterNameDiscoverer.getParameterNames(getMethod()); + this.parameterNames = parameterNames; } - return this.parameterNames; + return parameterNames; } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java index e76156bf8265..58f3c23b459f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -103,10 +103,11 @@ private boolean compiledByAjc(Class clazz) { @Override public void validate(Class aspectClass) throws AopConfigException { // If the parent has the annotation and isn't abstract it's an error - if (aspectClass.getSuperclass().getAnnotation(Aspect.class) != null && - !Modifier.isAbstract(aspectClass.getSuperclass().getModifiers())) { + Class superclass = aspectClass.getSuperclass(); + if (superclass.getAnnotation(Aspect.class) != null && + !Modifier.isAbstract(superclass.getModifiers())) { throw new AopConfigException("[" + aspectClass.getName() + "] cannot extend concrete aspect [" + - aspectClass.getSuperclass().getName() + "]"); + superclass.getName() + "]"); } AjType ajType = AjTypeSystem.getAjType(aspectClass); diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java index a3e73ed063e2..048cc603ccc1 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java @@ -127,9 +127,9 @@ public AspectMetadata(Class aspectClass, String aspectName) { */ private String findPerClause(Class aspectClass) { String str = aspectClass.getAnnotation(Aspect.class).value(); - str = str.substring(str.indexOf('(') + 1); - str = str.substring(0, str.length() - 1); - return str; + int beginIndex = str.indexOf('(') + 1; + int endIndex = str.length() - 1; + return str.substring(beginIndex, endIndex); } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java index 9160c6480026..d5fefcec81d0 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java @@ -56,7 +56,7 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst * introspect to create AJType metadata using the type returned for the * given bean name from the BeanFactory. * @param beanFactory the BeanFactory to obtain instance(s) from - * @param name name of the bean + * @param name the name of the bean */ public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name) { this(beanFactory, name, null); diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java index 85adb1daa7a4..8896f990ecbb 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -97,7 +97,7 @@ public List buildAspectJAdvisors() { } // We must be careful not to instantiate beans eagerly as in this case they // would be cached by the Spring container but would not have been weaved. - Class beanType = this.beanFactory.getType(beanName); + Class beanType = this.beanFactory.getType(beanName, false); if (beanType == null) { continue; } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java index 7bf8cec70540..5355b2bbb379 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,14 +56,15 @@ /** * Factory that can create Spring AOP Advisors given AspectJ classes from - * classes honoring the AspectJ 5 annotation syntax, using reflection to - * invoke the corresponding advice methods. + * classes honoring AspectJ's annotation syntax, using reflection to invoke the + * corresponding advice methods. * * @author Rod Johnson * @author Adrian Colyer * @author Juergen Hoeller * @author Ramnivas Laddad * @author Phillip Webb + * @author Sam Brannen * @since 2.0 */ @SuppressWarnings("serial") @@ -72,13 +73,17 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto private static final Comparator METHOD_COMPARATOR; static { + // Note: although @After is ordered before @AfterReturning and @AfterThrowing, + // an @After advice method will actually be invoked after @AfterReturning and + // @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation) + // invokes proceed() in a `try` block and only invokes the @After advice method + // in a corresponding `finally` block. Comparator adviceKindComparator = new ConvertingComparator<>( new InstanceComparator<>( Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class), (Converter) method -> { - AspectJAnnotation annotation = - AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method); - return (annotation != null ? annotation.getAnnotation() : null); + AspectJAnnotation ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method); + return (ann != null ? ann.getAnnotation() : null); }); Comparator methodNameComparator = new ConvertingComparator<>(Method::getName); METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator); @@ -123,7 +128,15 @@ public List getAdvisors(MetadataAwareAspectInstanceFactory aspectInstan List advisors = new ArrayList<>(); for (Method method : getAdvisorMethods(aspectClass)) { - Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); + // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect + // to getAdvisor(...) to represent the "current position" in the declared methods list. + // However, since Java 7 the "current position" is not valid since the JDK no longer + // returns declared methods in the order in which they are declared in the source code. + // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods + // discovered via reflection in order to support reliable advice ordering across JVM launches. + // Specifically, a value of 0 aligns with the default value used in + // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor). + Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName); if (advisor != null) { advisors.add(advisor); } @@ -154,7 +167,9 @@ private List getAdvisorMethods(Class aspectClass) { methods.add(method); } }, ReflectionUtils.USER_DECLARED_METHODS); - methods.sort(METHOD_COMPARATOR); + if (methods.size() > 1) { + methods.sort(METHOD_COMPARATOR); + } return methods; } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/autoproxy/AspectJAwareAdvisorAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/autoproxy/AspectJAwareAdvisorAutoProxyCreator.java index ea21644dc15c..2d2aabd07fae 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/autoproxy/AspectJAwareAdvisorAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/autoproxy/AspectJAwareAdvisorAutoProxyCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,27 +50,27 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx /** - * Sort the rest by AspectJ precedence. If two pieces of advice have - * come from the same aspect they will have the same order. - * Advice from the same aspect is then further ordered according to the + * Sort the supplied {@link Advisor} instances according to AspectJ precedence. + *

If two pieces of advice come from the same aspect, they will have the same + * order. Advice from the same aspect is then further ordered according to the * following rules: *

    - *
  • if either of the pair is after advice, then the advice declared - * last gets highest precedence (runs last)
  • - *
  • otherwise the advice declared first gets highest precedence (runs first)
  • + *
  • If either of the pair is after advice, then the advice declared + * last gets highest precedence (i.e., runs last).
  • + *
  • Otherwise the advice declared first gets highest precedence (i.e., runs + * first).
  • *
*

Important: Advisors are sorted in precedence order, from highest * precedence to lowest. "On the way in" to a join point, the highest precedence - * advisor should run first. "On the way out" of a join point, the highest precedence - * advisor should run last. + * advisor should run first. "On the way out" of a join point, the highest + * precedence advisor should run last. */ @Override - @SuppressWarnings("unchecked") protected List sortAdvisors(List advisors) { List partiallyComparableAdvisors = new ArrayList<>(advisors.size()); - for (Advisor element : advisors) { + for (Advisor advisor : advisors) { partiallyComparableAdvisors.add( - new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR)); + new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR)); } List sorted = PartialOrder.sort(partiallyComparableAdvisors); if (sorted != null) { @@ -86,8 +86,8 @@ protected List sortAdvisors(List advisors) { } /** - * Adds an {@link ExposeInvocationInterceptor} to the beginning of the advice chain. - * These additional advices are needed when using AspectJ expression pointcuts + * Add an {@link ExposeInvocationInterceptor} to the beginning of the advice chain. + *

This additional advice is needed when using AspectJ pointcut expressions * and when using AspectJ-style advice. */ @Override @@ -110,7 +110,7 @@ protected boolean shouldSkip(Class beanClass, String beanName) { /** - * Implements AspectJ PartialComparable interface for defining partial orderings. + * Implements AspectJ's {@link PartialComparable} interface for defining partial orderings. */ private static class PartiallyComparableAdvisorHolder implements PartialComparable { @@ -140,17 +140,19 @@ public Advisor getAdvisor() { @Override public String toString() { - StringBuilder sb = new StringBuilder(); Advice advice = this.advisor.getAdvice(); - sb.append(ClassUtils.getShortName(advice.getClass())); - sb.append(": "); + StringBuilder sb = new StringBuilder(ClassUtils.getShortName(advice.getClass())); + boolean appended = false; if (this.advisor instanceof Ordered) { - sb.append("order ").append(((Ordered) this.advisor).getOrder()).append(", "); + sb.append(": order = ").append(((Ordered) this.advisor).getOrder()); + appended = true; } if (advice instanceof AbstractAspectJAdvice) { + sb.append(!appended ? ": " : ", "); AbstractAspectJAdvice ajAdvice = (AbstractAspectJAdvice) advice; + sb.append("aspect name = "); sb.append(ajAdvice.getAspectName()); - sb.append(", declaration order "); + sb.append(", declaration order = "); sb.append(ajAdvice.getDeclarationOrder()); } return sb.toString(); diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/autoproxy/AspectJPrecedenceComparator.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/autoproxy/AspectJPrecedenceComparator.java index 64066f7c04e5..2d243fadc726 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/autoproxy/AspectJPrecedenceComparator.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/autoproxy/AspectJPrecedenceComparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,20 +27,22 @@ /** * Orders AspectJ advice/advisors by precedence (not invocation order). * - *

Given two pieces of advice, {@code a} and {@code b}: + *

Given two pieces of advice, {@code A} and {@code B}: *

    - *
  • if {@code a} and {@code b} are defined in different aspects, then the advice - * in the aspect with the lowest order value has the highest precedence
  • - *
  • if {@code a} and {@code b} are defined in the same aspect, then if one of - * {@code a} or {@code b} is a form of after advice, then the advice declared last - * in the aspect has the highest precedence. If neither {@code a} nor {@code b} is - * a form of after advice, then the advice declared first in the aspect has the - * highest precedence.
  • + *
  • If {@code A} and {@code B} are defined in different aspects, then the advice + * in the aspect with the lowest order value has the highest precedence.
  • + *
  • If {@code A} and {@code B} are defined in the same aspect, if one of + * {@code A} or {@code B} is a form of after advice, then the advice declared + * last in the aspect has the highest precedence. If neither {@code A} nor {@code B} + * is a form of after advice, then the advice declared first in the aspect + * has the highest precedence.
  • *
* - *

Important: Note that unlike a normal comparator a return of 0 means - * we don't care about the ordering, not that the two elements must be sorted - * identically. Used with AspectJ PartialOrder class. + *

Important: This comparator is used with AspectJ's + * {@link org.aspectj.util.PartialOrder PartialOrder} sorting utility. Thus, unlike + * a normal {@link Comparator}, a return value of {@code 0} from this comparator + * means we don't care about the ordering, not that the two elements must be sorted + * identically. * * @author Adrian Colyer * @author Juergen Hoeller @@ -59,16 +61,16 @@ class AspectJPrecedenceComparator implements Comparator { /** - * Create a default AspectJPrecedenceComparator. + * Create a default {@code AspectJPrecedenceComparator}. */ public AspectJPrecedenceComparator() { this.advisorComparator = AnnotationAwareOrderComparator.INSTANCE; } /** - * Create a AspectJPrecedenceComparator, using the given Comparator + * Create an {@code AspectJPrecedenceComparator}, using the given {@link Comparator} * for comparing {@link org.springframework.aop.Advisor} instances. - * @param advisorComparator the Comparator to use for Advisors + * @param advisorComparator the {@code Comparator} to use for advisors */ public AspectJPrecedenceComparator(Comparator advisorComparator) { Assert.notNull(advisorComparator, "Advisor comparator must not be null"); @@ -125,27 +127,21 @@ private boolean declaredInSameAspect(Advisor advisor1, Advisor advisor2) { getAspectName(advisor1).equals(getAspectName(advisor2))); } - private boolean hasAspectName(Advisor anAdvisor) { - return (anAdvisor instanceof AspectJPrecedenceInformation || - anAdvisor.getAdvice() instanceof AspectJPrecedenceInformation); + private boolean hasAspectName(Advisor advisor) { + return (advisor instanceof AspectJPrecedenceInformation || + advisor.getAdvice() instanceof AspectJPrecedenceInformation); } // pre-condition is that hasAspectName returned true - private String getAspectName(Advisor anAdvisor) { - AspectJPrecedenceInformation pi = AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor); - Assert.state(pi != null, "Unresolvable precedence information"); - return pi.getAspectName(); + private String getAspectName(Advisor advisor) { + AspectJPrecedenceInformation precedenceInfo = AspectJAopUtils.getAspectJPrecedenceInformationFor(advisor); + Assert.state(precedenceInfo != null, () -> "Unresolvable AspectJPrecedenceInformation for " + advisor); + return precedenceInfo.getAspectName(); } - private int getAspectDeclarationOrder(Advisor anAdvisor) { - AspectJPrecedenceInformation precedenceInfo = - AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor); - if (precedenceInfo != null) { - return precedenceInfo.getDeclarationOrder(); - } - else { - return 0; - } + private int getAspectDeclarationOrder(Advisor advisor) { + AspectJPrecedenceInformation precedenceInfo = AspectJAopUtils.getAspectJPrecedenceInformationFor(advisor); + return (precedenceInfo != null ? precedenceInfo.getDeclarationOrder() : 0); } } diff --git a/spring-aop/src/main/java/org/springframework/aop/config/AdviceEntry.java b/spring-aop/src/main/java/org/springframework/aop/config/AdviceEntry.java index f9869a5f9b10..7d9b2ad2dc82 100644 --- a/spring-aop/src/main/java/org/springframework/aop/config/AdviceEntry.java +++ b/spring-aop/src/main/java/org/springframework/aop/config/AdviceEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,13 +30,14 @@ public class AdviceEntry implements ParseState.Entry { /** - * Creates a new instance of the {@link AdviceEntry} class. - * @param kind the kind of advice represented by this entry (before, after, around, etc.) + * Create a new {@code AdviceEntry} instance. + * @param kind the kind of advice represented by this entry (before, after, around) */ public AdviceEntry(String kind) { this.kind = kind; } + @Override public String toString() { return "Advice (" + this.kind + ")"; diff --git a/spring-aop/src/main/java/org/springframework/aop/config/AdvisorEntry.java b/spring-aop/src/main/java/org/springframework/aop/config/AdvisorEntry.java index 1f7ba059620a..1a8b45c4823f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/config/AdvisorEntry.java +++ b/spring-aop/src/main/java/org/springframework/aop/config/AdvisorEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,13 +30,14 @@ public class AdvisorEntry implements ParseState.Entry { /** - * Creates a new instance of the {@link AdvisorEntry} class. + * Create a new {@code AdvisorEntry} instance. * @param name the bean name of the advisor */ public AdvisorEntry(String name) { this.name = name; } + @Override public String toString() { return "Advisor '" + this.name + "'"; diff --git a/spring-aop/src/main/java/org/springframework/aop/config/AopNamespaceHandler.java b/spring-aop/src/main/java/org/springframework/aop/config/AopNamespaceHandler.java index 99eb2fa6f594..fa6cc80a1f3c 100644 --- a/spring-aop/src/main/java/org/springframework/aop/config/AopNamespaceHandler.java +++ b/spring-aop/src/main/java/org/springframework/aop/config/AopNamespaceHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,12 +61,12 @@ public class AopNamespaceHandler extends NamespaceHandlerSupport { */ @Override public void init() { - // In 2.0 XSD as well as in 2.1 XSD. + // In 2.0 XSD as well as in 2.5+ XSDs registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); - // Only in 2.0 XSD: moved to context namespace as of 2.1 + // Only in 2.0 XSD: moved to context namespace in 2.5+ registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); } diff --git a/spring-aop/src/main/java/org/springframework/aop/config/AspectEntry.java b/spring-aop/src/main/java/org/springframework/aop/config/AspectEntry.java index 13633bc2a27c..2d4360048cf7 100644 --- a/spring-aop/src/main/java/org/springframework/aop/config/AspectEntry.java +++ b/spring-aop/src/main/java/org/springframework/aop/config/AspectEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,7 @@ public class AspectEntry implements ParseState.Entry { /** - * Create a new AspectEntry. + * Create a new {@code AspectEntry} instance. * @param id the id of the aspect element * @param ref the bean name referenced by this aspect element */ @@ -43,6 +43,7 @@ public AspectEntry(String id, String ref) { this.ref = ref; } + @Override public String toString() { return "Aspect: " + (StringUtils.hasLength(this.id) ? "id='" + this.id + "'" : "ref='" + this.ref + "'"); diff --git a/spring-aop/src/main/java/org/springframework/aop/config/PointcutEntry.java b/spring-aop/src/main/java/org/springframework/aop/config/PointcutEntry.java index 950f8da387e7..e6066c513ee9 100644 --- a/spring-aop/src/main/java/org/springframework/aop/config/PointcutEntry.java +++ b/spring-aop/src/main/java/org/springframework/aop/config/PointcutEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,14 +28,16 @@ public class PointcutEntry implements ParseState.Entry { private final String name; + /** - * Creates a new instance of the {@link PointcutEntry} class. + * Create a new {@code PointcutEntry} instance. * @param name the bean name of the pointcut */ public PointcutEntry(String name) { this.name = name; } + @Override public String toString() { return "Pointcut '" + this.name + "'"; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java index 6882e97cc9fd..bb680a3477b5 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java @@ -189,7 +189,7 @@ else if (!isProxyTargetClass()) { /** * Determine a TargetSource for the given target (or TargetSource). - * @param target target. If this is an implementation of TargetSource it is + * @param target the target. If this is an implementation of TargetSource it is * used as our TargetSource; otherwise it is wrapped in a SingletonTargetSource. * @return a TargetSource for this object */ diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/Advised.java b/spring-aop/src/main/java/org/springframework/aop/framework/Advised.java index 3deb11bb2a1d..035ae8b30f9a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/Advised.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/Advised.java @@ -142,7 +142,7 @@ public interface Advised extends TargetClassAware { /** * Remove the advisor at the given index. - * @param index index of advisor to remove + * @param index the index of advisor to remove * @throws AopConfigException if the index is invalid */ void removeAdvisor(int index) throws AopConfigException; @@ -177,7 +177,7 @@ public interface Advised extends TargetClassAware { *

Note that the given advice will apply to all invocations on the proxy, * even to the {@code toString()} method! Use appropriate advice implementations * or specify appropriate pointcuts to apply to a narrower set of methods. - * @param advice advice to add to the tail of the chain + * @param advice the advice to add to the tail of the chain * @throws AopConfigException in case of invalid advice * @see #addAdvice(int, Advice) * @see org.springframework.aop.support.DefaultPointcutAdvisor @@ -193,7 +193,7 @@ public interface Advised extends TargetClassAware { * even to the {@code toString()} method! Use appropriate advice implementations * or specify appropriate pointcuts to apply to a narrower set of methods. * @param pos index from 0 (head) - * @param advice advice to add at the specified position in the advice chain + * @param advice the advice to add at the specified position in the advice chain * @throws AopConfigException in case of invalid advice */ void addAdvice(int pos, Advice advice) throws AopConfigException; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java index a82e77a0f1b9..b4de26beedfe 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -283,16 +283,15 @@ public void removeAdvisor(int index) throws AopConfigException { "This configuration only has " + this.advisors.size() + " advisors."); } - Advisor advisor = this.advisors.get(index); + Advisor advisor = this.advisors.remove(index); if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; // We need to remove introduction interfaces. - for (int j = 0; j < ia.getInterfaces().length; j++) { - removeInterface(ia.getInterfaces()[j]); + for (Class ifc : ia.getInterfaces()) { + removeInterface(ifc); } } - this.advisors.remove(index); updateAdvisorArray(); adviceChanged(); } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AopContext.java b/spring-aop/src/main/java/org/springframework/aop/framework/AopContext.java index 36b5635d4abf..9653ced6bc8b 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AopContext.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AopContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -67,7 +67,8 @@ public static Object currentProxy() throws IllegalStateException { Object proxy = currentProxy.get(); if (proxy == null) { throw new IllegalStateException( - "Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available."); + "Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and " + + "ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context."); } return proxy; } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java b/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java index a501d4614f27..e417f6ebed6b 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java @@ -224,8 +224,8 @@ static Object[] adaptArgumentsIfNecessary(Method method, @Nullable Object[] argu return new Object[0]; } if (method.isVarArgs()) { - Class[] paramTypes = method.getParameterTypes(); - if (paramTypes.length == arguments.length) { + if (method.getParameterCount() == arguments.length) { + Class[] paramTypes = method.getParameterTypes(); int varargIndex = paramTypes.length - 1; Class varargType = paramTypes[varargIndex]; if (varargType.isArray()) { diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java index 1e899671aaaf..f37a4076aec1 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,7 @@ import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import org.springframework.cglib.proxy.NoOp; +import org.springframework.core.KotlinDetector; import org.springframework.core.SmartClassLoader; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -236,7 +237,7 @@ protected Enhancer createEnhancer() { * validates it if not. */ private void validateClassIfNecessary(Class proxySuperClass, @Nullable ClassLoader proxyClassLoader) { - if (logger.isWarnEnabled()) { + if (logger.isInfoEnabled()) { synchronized (validatedClasses) { if (!validatedClasses.containsKey(proxySuperClass)) { doValidateClass(proxySuperClass, proxyClassLoader, @@ -258,15 +259,17 @@ private void doValidateClass(Class proxySuperClass, @Nullable ClassLoader pro int mod = method.getModifiers(); if (!Modifier.isStatic(mod) && !Modifier.isPrivate(mod)) { if (Modifier.isFinal(mod)) { - if (implementsInterface(method, ifcs)) { + if (logger.isInfoEnabled() && implementsInterface(method, ifcs)) { logger.info("Unable to proxy interface-implementing method [" + method + "] because " + "it is marked as final: Consider using interface-based JDK proxies instead!"); } - logger.debug("Final method [" + method + "] cannot get proxied via CGLIB: " + - "Calls to this method will NOT be routed to the target instance and " + - "might lead to NPEs against uninitialized fields in the proxy instance."); + if (logger.isDebugEnabled()) { + logger.debug("Final method [" + method + "] cannot get proxied via CGLIB: " + + "Calls to this method will NOT be routed to the target instance and " + + "might lead to NPEs against uninitialized fields in the proxy instance."); + } } - else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) && + else if (logger.isDebugEnabled() && !Modifier.isPublic(mod) && !Modifier.isProtected(mod) && proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) { logger.debug("Method [" + method + "] is package-visible across different ClassLoaders " + "and cannot get proxied via CGLIB: Declare this method as public or protected " + @@ -365,7 +368,7 @@ public int hashCode() { */ private static boolean implementsInterface(Method method, Set> ifcs) { for (Class ifc : ifcs) { - if (ClassUtils.hasMethod(ifc, method.getName(), method.getParameterTypes())) { + if (ClassUtils.hasMethod(ifc, method)) { return true; } } @@ -526,7 +529,7 @@ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy private static class StaticDispatcher implements Dispatcher, Serializable { @Nullable - private Object target; + private final Object target; public StaticDispatcher(@Nullable Object target) { this.target = target; @@ -552,7 +555,7 @@ public AdvisedDispatcher(AdvisedSupport advised) { } @Override - public Object loadObject() throws Exception { + public Object loadObject() { return this.advised; } } @@ -676,13 +679,19 @@ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. - if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { + if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) { // We can skip creating a MethodInvocation: just invoke the target directly. // Note that the final invoker must be an InvokerInterceptor, so we know // it does nothing but a reflective operation on the target, and no hot // swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); - retVal = methodProxy.invoke(target, argsToUse); + try { + retVal = methodProxy.invoke(target, argsToUse); + } + catch (CodeGenerationException ex) { + CglibMethodInvocation.logFastClassGenerationFailure(method); + retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); + } } else { // We need to create a method invocation... @@ -734,10 +743,7 @@ public CglibMethodInvocation(Object proxy, @Nullable Object target, Method metho super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers); // Only use method proxy for public methods not derived from java.lang.Object - this.methodProxy = (Modifier.isPublic(method.getModifiers()) && - method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) && - !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ? - methodProxy : null); + this.methodProxy = (isMethodProxyCompatible(method) ? methodProxy : null); } @Override @@ -750,10 +756,17 @@ public Object proceed() throws Throwable { throw ex; } catch (Exception ex) { - if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) { + if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) || + KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) { + // Propagate original exception if declared on the target method + // (with callers expecting it). Always propagate it for Kotlin code + // since checked exceptions do not have to be explicitly declared there. throw ex; } else { + // Checked exception thrown in the interceptor but not declared on the + // target method signature -> apply an UndeclaredThrowableException, + // aligned with standard JDK dynamic proxy behavior. throw new UndeclaredThrowableException(ex); } } @@ -766,10 +779,25 @@ public Object proceed() throws Throwable { @Override protected Object invokeJoinpoint() throws Throwable { if (this.methodProxy != null) { - return this.methodProxy.invoke(this.target, this.arguments); + try { + return this.methodProxy.invoke(this.target, this.arguments); + } + catch (CodeGenerationException ex) { + logFastClassGenerationFailure(this.method); + } } - else { - return super.invokeJoinpoint(); + return super.invokeJoinpoint(); + } + + static boolean isMethodProxyCompatible(Method method) { + return (Modifier.isPublic(method.getModifiers()) && + method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) && + !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method)); + } + + static void logFastClassGenerationFailure(Method method) { + if (logger.isDebugEnabled()) { + logger.debug("Failed to generate CGLIB fast class for method: " + method); } } } @@ -872,15 +900,14 @@ public int accept(Method method) { } return AOP_PROXY; } - Method key = method; // Check to see if we have fixed interceptor to serve this method. // Else use the AOP_PROXY. - if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) { + if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(method)) { if (logger.isTraceEnabled()) { logger.trace("Method has advice and optimizations are enabled: " + method); } // We know that we are optimizing so we can use the FixedStaticChainInterceptors. - int index = this.fixedInterceptorMap.get(key); + int index = this.fixedInterceptorMap.get(method); return (index + this.fixedInterceptorOffset); } else { @@ -959,11 +986,11 @@ public boolean equals(@Nullable Object other) { return true; } - private boolean equalsAdviceClasses(Advisor a, Advisor b) { + private static boolean equalsAdviceClasses(Advisor a, Advisor b) { return (a.getAdvice().getClass() == b.getAdvice().getClass()); } - private boolean equalsPointcuts(Advisor a, Advisor b) { + private static boolean equalsPointcuts(Advisor a, Advisor b) { // If only one of the advisor (but not both) is PointcutAdvisor, then it is a mismatch. // Takes care of the situations where an IntroductionAdvisor is used (see SPR-3959). return (!(a instanceof PointcutAdvisor) || diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java index d304397b568d..0a072316f4cc 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,9 +43,11 @@ * @see AdvisedSupport#setProxyTargetClass * @see AdvisedSupport#setInterfaces */ -@SuppressWarnings("serial") public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { + private static final long serialVersionUID = 7930414337282325166L; + + @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java index c9c081c47497..5e1ed1603fa6 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.aopalliance.aop.Advice; import org.aopalliance.intercept.Interceptor; @@ -342,11 +340,8 @@ private synchronized Object newPrototypeInstance() { // an independent instance of the configuration. // In this case, no proxy will have an instance of this object's configuration, // but will have an independent copy. - if (logger.isTraceEnabled()) { - logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this); - } - ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory()); + // The copy needs a fresh advisor chain, and a fresh TargetSource. TargetSource targetSource = freshTargetSource(); copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain()); @@ -359,9 +354,6 @@ private synchronized Object newPrototypeInstance() { } copy.setFrozen(this.freezeProxy); - if (logger.isTraceEnabled()) { - logger.trace("Using ProxyCreatorSupport copy: " + copy); - } return getProxy(copy.createAopProxy()); } @@ -429,11 +421,7 @@ private boolean isNamedBeanAnAdvisorOrAdvice(String beanName) { * are unaffected by such changes. */ private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { - if (this.advisorChainInitialized) { - return; - } - - if (!ObjectUtils.isEmpty(this.interceptorNames)) { + if (!this.advisorChainInitialized && !ObjectUtils.isEmpty(this.interceptorNames)) { if (this.beanFactory == null) { throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames)); @@ -447,16 +435,12 @@ private synchronized void initializeAdvisorChain() throws AopConfigException, Be // Materialize interceptor chain from bean names. for (String name : this.interceptorNames) { - if (logger.isTraceEnabled()) { - logger.trace("Configuring advisor or advice '" + name + "'"); - } - if (name.endsWith(GLOBAL_SUFFIX)) { if (!(this.beanFactory instanceof ListableBeanFactory)) { throw new AopConfigException( "Can only use global advisors or interceptors with a ListableBeanFactory"); } - addGlobalAdvisor((ListableBeanFactory) this.beanFactory, + addGlobalAdvisors((ListableBeanFactory) this.beanFactory, name.substring(0, name.length() - GLOBAL_SUFFIX.length())); } @@ -473,12 +457,12 @@ private synchronized void initializeAdvisorChain() throws AopConfigException, Be // Avoid unnecessary creation of prototype bean just for advisor chain initialization. advice = new PrototypePlaceholderAdvisor(name); } - addAdvisorOnChainCreation(advice, name); + addAdvisorOnChainCreation(advice); } } - } - this.advisorChainInitialized = true; + this.advisorChainInitialized = true; + } } @@ -496,11 +480,10 @@ private List freshAdvisorChain() { if (logger.isDebugEnabled()) { logger.debug("Refreshing bean named '" + pa.getBeanName() + "'"); } - // Replace the placeholder with a fresh prototype instance resulting - // from a getBean() lookup + // Replace the placeholder with a fresh prototype instance resulting from a getBean lookup if (this.beanFactory == null) { - throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + - "- cannot resolve prototype advisor '" + pa.getBeanName() + "'"); + throw new IllegalStateException("No BeanFactory available anymore (probably due to " + + "serialization) - cannot resolve prototype advisor '" + pa.getBeanName() + "'"); } Object bean = this.beanFactory.getBean(pa.getBeanName()); Advisor refreshedAdvisor = namedBeanToAdvisor(bean); @@ -517,28 +500,26 @@ private List freshAdvisorChain() { /** * Add all global interceptors and pointcuts. */ - private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) { + private void addGlobalAdvisors(ListableBeanFactory beanFactory, String prefix) { String[] globalAdvisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class); String[] globalInterceptorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class); - List beans = new ArrayList<>(globalAdvisorNames.length + globalInterceptorNames.length); - Map names = new HashMap<>(beans.size()); - for (String name : globalAdvisorNames) { - Object bean = beanFactory.getBean(name); - beans.add(bean); - names.put(bean, name); - } - for (String name : globalInterceptorNames) { - Object bean = beanFactory.getBean(name); - beans.add(bean); - names.put(bean, name); - } - AnnotationAwareOrderComparator.sort(beans); - for (Object bean : beans) { - String name = names.get(bean); - if (name.startsWith(prefix)) { - addAdvisorOnChainCreation(bean, name); + if (globalAdvisorNames.length > 0 || globalInterceptorNames.length > 0) { + List beans = new ArrayList<>(globalAdvisorNames.length + globalInterceptorNames.length); + for (String name : globalAdvisorNames) { + if (name.startsWith(prefix)) { + beans.add(beanFactory.getBean(name)); + } + } + for (String name : globalInterceptorNames) { + if (name.startsWith(prefix)) { + beans.add(beanFactory.getBean(name)); + } + } + AnnotationAwareOrderComparator.sort(beans); + for (Object bean : beans) { + addAdvisorOnChainCreation(bean); } } } @@ -549,17 +530,11 @@ private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) { * Because of these three possibilities, we can't type the signature * more strongly. * @param next advice, advisor or target object - * @param name bean name from which we obtained this object in our owning - * bean factory */ - private void addAdvisorOnChainCreation(Object next, String name) { + private void addAdvisorOnChainCreation(Object next) { // We need to convert to an Advisor if necessary so that our source reference // matches what we find from superclass interceptors. - Advisor advisor = namedBeanToAdvisor(next); - if (logger.isTraceEnabled()) { - logger.trace("Adding advisor with name '" + name + "'"); - } - addAdvisor(advisor); + addAdvisor(namedBeanToAdvisor(next)); } /** @@ -570,9 +545,7 @@ private void addAdvisorOnChainCreation(Object next, String name) { */ private TargetSource freshTargetSource() { if (this.targetName == null) { - if (logger.isTraceEnabled()) { - logger.trace("Not refreshing target: Bean name not specified in 'interceptorNames'."); - } + // Not refreshing target: bean name not specified in 'interceptorNames' return this.targetSource; } else { @@ -600,8 +573,8 @@ private Advisor namedBeanToAdvisor(Object next) { // We expected this to be an Advisor or Advice, // but it wasn't. This is a configuration error. throw new AopConfigException("Unknown advisor type " + next.getClass() + - "; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," + - "which may also be target or TargetSource", ex); + "; can only include Advisor or Advice type beans in interceptorNames chain " + + "except for last entry which may also be target instance or TargetSource", ex); } } @@ -612,7 +585,7 @@ private Advisor namedBeanToAdvisor(Object next) { protected void adviceChanged() { super.adviceChanged(); if (this.singleton) { - logger.debug("Advice has changed; recaching singleton instance"); + logger.debug("Advice has changed; re-caching singleton instance"); synchronized (this) { this.singletonInstance = null; } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java b/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java index 0eef701a932f..1db34223cb41 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java @@ -212,8 +212,7 @@ public MethodInvocation invocableClone() { Object[] cloneArguments = this.arguments; if (this.arguments.length > 0) { // Build an independent copy of the arguments array. - cloneArguments = new Object[this.arguments.length]; - System.arraycopy(this.arguments, 0, cloneArguments, 0, this.arguments.length); + cloneArguments = this.arguments.clone(); } return invocableClone(cloneArguments); } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/adapter/MethodBeforeAdviceInterceptor.java b/spring-aop/src/main/java/org/springframework/aop/framework/adapter/MethodBeforeAdviceInterceptor.java index 420c6203fba3..342de103da46 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/adapter/MethodBeforeAdviceInterceptor.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/adapter/MethodBeforeAdviceInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,9 +26,9 @@ import org.springframework.util.Assert; /** - * Interceptor to wrap am {@link org.springframework.aop.MethodBeforeAdvice}. - * Used internally by the AOP framework; application developers should not need - * to use this class directly. + * Interceptor to wrap a {@link MethodBeforeAdvice}. + *

Used internally by the AOP framework; application developers should not + * need to use this class directly. * * @author Rod Johnson * @see AfterReturningAdviceInterceptor diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.java index f169de2a7a03..4900c3d4657c 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAdvisorAutoProxyCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,11 +36,13 @@ * also override the inherited {@link #shouldSkip} method to exclude certain * objects from auto-proxying. * - *

Advisors or advices requiring ordering should implement the + *

Advisors or advices requiring ordering should be annotated with + * {@link org.springframework.core.annotation.Order @Order} or implement the * {@link org.springframework.core.Ordered} interface. This class sorts - * Advisors by Ordered order value. Advisors that don't implement the - * Ordered interface will be considered as unordered; they will appear - * at the end of the advisor chain in undefined order. + * advisors using the {@link AnnotationAwareOrderComparator}. Advisors that are + * not annotated with {@code @Order} or don't implement the {@code Ordered} + * interface will be considered as unordered; they will appear at the end of the + * advisor chain in an undefined order. * * @author Rod Johnson * @author Juergen Hoeller diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java index 50a9734bdf4a..2a63c676b7c5 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.aop.framework.autoproxy; import java.lang.reflect.Constructor; +import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -449,7 +450,17 @@ protected Object createProxy(Class beanClass, @Nullable String beanName, ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); - if (!proxyFactory.isProxyTargetClass()) { + if (proxyFactory.isProxyTargetClass()) { + // Explicit handling of JDK proxy targets (for introduction advice scenarios) + if (Proxy.isProxyClass(beanClass)) { + // Must allow for introductions; can't just set interfaces to the proxy's interfaces only. + for (Class ifc : beanClass.getInterfaces()) { + proxyFactory.addInterface(ifc); + } + } + } + else { + // No proxyTargetClass flag enforced, let's apply our default checks... if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } @@ -513,7 +524,10 @@ protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] List allInterceptors = new ArrayList<>(); if (specificInterceptors != null) { - allInterceptors.addAll(Arrays.asList(specificInterceptors)); + if (specificInterceptors.length > 0) { + // specificInterceptors may equals PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS + allInterceptors.addAll(Arrays.asList(specificInterceptors)); + } if (commonInterceptors.length > 0) { if (this.applyCommonInterceptorsFirst) { allInterceptors.addAll(0, Arrays.asList(commonInterceptors)); diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/AbstractMonitoringInterceptor.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/AbstractMonitoringInterceptor.java index 494de786e5ac..536e6e3ade39 100644 --- a/spring-aop/src/main/java/org/springframework/aop/interceptor/AbstractMonitoringInterceptor.java +++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/AbstractMonitoringInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -103,7 +103,8 @@ protected String createInvocationTraceName(MethodInvocation invocation) { if (this.logTargetClassInvocation && clazz.isInstance(invocation.getThis())) { clazz = invocation.getThis().getClass(); } - return getPrefix() + clazz.getName() + '.' + method.getName() + getSuffix(); + String className = clazz.getName(); + return getPrefix() + className + '.' + method.getName() + getSuffix(); } } diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/CustomizableTraceInterceptor.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/CustomizableTraceInterceptor.java index 48fc03aee10b..e6008ee001ea 100644 --- a/spring-aop/src/main/java/org/springframework/aop/interceptor/CustomizableTraceInterceptor.java +++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/CustomizableTraceInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -147,7 +147,7 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor { /** * The {@code Pattern} used to match placeholders. */ - private static final Pattern PATTERN = Pattern.compile("\\$\\[\\p{Alpha}+\\]"); + private static final Pattern PATTERN = Pattern.compile("\\$\\[\\p{Alpha}+]"); /** * The {@code Set} of allowed placeholders. diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/ExposeInvocationInterceptor.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/ExposeInvocationInterceptor.java index 3b3f62fa7cc5..6c14533b3959 100644 --- a/spring-aop/src/main/java/org/springframework/aop/interceptor/ExposeInvocationInterceptor.java +++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/ExposeInvocationInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -71,9 +71,11 @@ public static MethodInvocation currentInvocation() throws IllegalStateException MethodInvocation mi = invocation.get(); if (mi == null) { throw new IllegalStateException( - "No MethodInvocation found: Check that an AOP invocation is in progress, and that the " + + "No MethodInvocation found: Check that an AOP invocation is in progress and that the " + "ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " + - "advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!"); + "advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor! " + + "In addition, ExposeInvocationInterceptor and ExposeInvocationInterceptor.currentInvocation() " + + "must be invoked from the same thread."); } return mi; } diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/SimpleTraceInterceptor.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/SimpleTraceInterceptor.java index 147408f24808..87d6186d2914 100644 --- a/spring-aop/src/main/java/org/springframework/aop/interceptor/SimpleTraceInterceptor.java +++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/SimpleTraceInterceptor.java @@ -73,8 +73,8 @@ protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throw * @return the description */ protected String getInvocationDescription(MethodInvocation invocation) { - return "method '" + invocation.getMethod().getName() + "' of class [" + - invocation.getThis().getClass().getName() + "]"; + String className = invocation.getThis().getClass().getName(); + return "method '" + invocation.getMethod().getName() + "' of class [" + className + "]"; } } diff --git a/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyUtils.java b/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyUtils.java index cc3d00da8488..e1899cf8e5bc 100644 --- a/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyUtils.java @@ -124,8 +124,8 @@ public static String getOriginalBeanName(@Nullable String targetBeanName) { } /** - * Specify if the {@code beanName} is the name of a bean that references the target - * bean within a scoped proxy. + * Determine if the {@code beanName} is the name of a bean that references + * the target bean within a scoped proxy. * @since 4.1.4 */ public static boolean isScopedTarget(@Nullable String beanName) { diff --git a/spring-aop/src/main/java/org/springframework/aop/support/AbstractExpressionPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/AbstractExpressionPointcut.java index b4218508edb0..5330f2c00d64 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/AbstractExpressionPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/AbstractExpressionPointcut.java @@ -78,7 +78,7 @@ public void setExpression(@Nullable String expression) { * Called when a new pointcut expression is set. * The expression should be parsed at this point if possible. *

This implementation is empty. - * @param expression expression to set + * @param expression the expression to set * @throws IllegalArgumentException if the expression is invalid * @see #setExpression */ diff --git a/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java index d76cdd725374..ff2370a32233 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -71,7 +71,8 @@ public DefaultIntroductionAdvisor(Advice advice, @Nullable IntroductionInfo intr if (introductionInfo != null) { Class[] introducedInterfaces = introductionInfo.getInterfaces(); if (introducedInterfaces.length == 0) { - throw new IllegalArgumentException("IntroductionAdviceSupport implements no interfaces"); + throw new IllegalArgumentException( + "IntroductionInfo defines no interfaces to introduce: " + introductionInfo); } for (Class ifc : introducedInterfaces) { addInterface(ifc); diff --git a/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java index faf1b0f4f3a0..d3d762465d51 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java @@ -66,7 +66,7 @@ public void setMappedNames(String... mappedNames) { * before a proxy is used. *

NB: This method does not work after the proxy is in * use, as advice chains will be cached. - * @param name name of the additional method that will match + * @param name the name of the additional method that will match * @return this pointcut to allow for multiple additions in one line */ public NameMatchMethodPointcut addMethodName(String name) { diff --git a/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcutAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcutAdvisor.java index 458b06de73c6..a7efd815dc5f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcutAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcutAdvisor.java @@ -76,7 +76,7 @@ public void setMappedNames(String... mappedNames) { * Add another eligible method name, in addition to those already named. * Like the set methods, this method is for use when configuring proxies, * before a proxy is used. - * @param name name of the additional method that will match + * @param name the name of the additional method that will match * @return this pointcut to allow for multiple additions in one line * @see NameMatchMethodPointcut#addMethodName */ diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutTests.java index 2ba65e3502b4..008df78e64d9 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/AspectJExpressionPointcutTests.java @@ -31,10 +31,10 @@ import org.springframework.aop.Pointcut; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.DefaultPointcutAdvisor; -import org.springframework.tests.sample.beans.IOther; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.tests.sample.beans.subpkg.DeepBean; +import org.springframework.beans.testfixture.beans.IOther; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.beans.testfixture.beans.subpkg.DeepBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -67,7 +67,7 @@ public void setUp() throws NoSuchMethodException { @Test public void testMatchExplicit() { - String expression = "execution(int org.springframework.tests.sample.beans.TestBean.getAge())"; + String expression = "execution(int org.springframework.beans.testfixture.beans.TestBean.getAge())"; Pointcut pointcut = getPointcut(expression); ClassFilter classFilter = pointcut.getClassFilter(); @@ -117,8 +117,8 @@ public void testTarget() throws SecurityException, NoSuchMethodException { * @param which this or target */ private void testThisOrTarget(String which) throws SecurityException, NoSuchMethodException { - String matchesTestBean = which + "(org.springframework.tests.sample.beans.TestBean)"; - String matchesIOther = which + "(org.springframework.tests.sample.beans.IOther)"; + String matchesTestBean = which + "(org.springframework.beans.testfixture.beans.TestBean)"; + String matchesIOther = which + "(org.springframework.beans.testfixture.beans.IOther)"; AspectJExpressionPointcut testBeanPc = new AspectJExpressionPointcut(); testBeanPc.setExpression(matchesTestBean); @@ -142,7 +142,7 @@ public void testWithinRootAndSubpackages() throws SecurityException, NoSuchMetho } private void testWithinPackage(boolean matchSubpackages) throws SecurityException, NoSuchMethodException { - String withinBeansPackage = "within(org.springframework.tests.sample.beans."; + String withinBeansPackage = "within(org.springframework.beans.testfixture.beans."; // Subpackages are matched by ** if (matchSubpackages) { withinBeansPackage += "."; @@ -187,7 +187,7 @@ public void testFriendlyErrorOnNoLocation3ArgMatching() { @Test public void testMatchWithArgs() throws Exception { - String expression = "execution(void org.springframework.tests.sample.beans.TestBean.setSomeNumber(Number)) && args(Double)"; + String expression = "execution(void org.springframework.beans.testfixture.beans.TestBean.setSomeNumber(Number)) && args(Double)"; Pointcut pointcut = getPointcut(expression); ClassFilter classFilter = pointcut.getClassFilter(); @@ -206,7 +206,7 @@ public void testMatchWithArgs() throws Exception { @Test public void testSimpleAdvice() { - String expression = "execution(int org.springframework.tests.sample.beans.TestBean.getAge())"; + String expression = "execution(int org.springframework.beans.testfixture.beans.TestBean.getAge())"; CallCountingInterceptor interceptor = new CallCountingInterceptor(); TestBean testBean = getAdvisedProxy(expression, interceptor); @@ -219,7 +219,7 @@ public void testSimpleAdvice() { @Test public void testDynamicMatchingProxy() { - String expression = "execution(void org.springframework.tests.sample.beans.TestBean.setSomeNumber(Number)) && args(Double)"; + String expression = "execution(void org.springframework.beans.testfixture.beans.TestBean.setSomeNumber(Number)) && args(Double)"; CallCountingInterceptor interceptor = new CallCountingInterceptor(); TestBean testBean = getAdvisedProxy(expression, interceptor); @@ -233,7 +233,7 @@ public void testDynamicMatchingProxy() { @Test public void testInvalidExpression() { - String expression = "execution(void org.springframework.tests.sample.beans.TestBean.setSomeNumber(Number) && args(Double)"; + String expression = "execution(void org.springframework.beans.testfixture.beans.TestBean.setSomeNumber(Number) && args(Double)"; assertThatIllegalArgumentException().isThrownBy( getPointcut(expression)::getClassFilter); // call to getClassFilter forces resolution } @@ -264,7 +264,7 @@ private void assertMatchesTestBeanClass(ClassFilter classFilter) { @Test public void testWithUnsupportedPointcutPrimitive() { - String expression = "call(int org.springframework.tests.sample.beans.TestBean.getAge())"; + String expression = "call(int org.springframework.beans.testfixture.beans.TestBean.getAge())"; assertThatExceptionOfType(UnsupportedPointcutPrimitiveException.class).isThrownBy(() -> getPointcut(expression).getClassFilter()) // call to getClassFilter forces resolution... .satisfies(ex -> assertThat(ex.getUnsupportedPrimitive()).isEqualTo(PointcutPrimitive.CALL)); diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutMatchingTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutMatchingTests.java index 37787c686464..3fd1b1e0c844 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutMatchingTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/BeanNamePointcutMatchingTests.java @@ -18,7 +18,7 @@ import org.junit.jupiter.api.Test; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java index 13c911c3343a..4591b74624aa 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java @@ -33,8 +33,8 @@ import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.interceptor.ExposeInvocationInterceptor; import org.springframework.aop.support.AopUtils; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/TigerAspectJExpressionPointcutTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/TigerAspectJExpressionPointcutTests.java index 5e9acc89d426..23d63fb1bea0 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/TigerAspectJExpressionPointcutTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/TigerAspectJExpressionPointcutTests.java @@ -27,7 +27,7 @@ import test.annotation.transaction.Tx; import org.springframework.aop.framework.ProxyFactory; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; @@ -56,7 +56,7 @@ public void setup() throws NoSuchMethodException { @Test public void testMatchGenericArgument() { - String expression = "execution(* set*(java.util.List) )"; + String expression = "execution(* set*(java.util.List) )"; AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(); ajexp.setExpression(expression); diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java index a69b4c76b2a5..bac21dadf9fc 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java @@ -87,7 +87,7 @@ public void testManualProxyJavaWithStaticPointcutAndTwoClassLoaders() throws Exc testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, new TestServiceImpl(), "TestServiceImpl"); // Then try again with a different class loader on the target... - SimpleThrowawayClassLoader loader = new SimpleThrowawayClassLoader(new TestServiceImpl().getClass().getClassLoader()); + SimpleThrowawayClassLoader loader = new SimpleThrowawayClassLoader(TestServiceImpl.class.getClassLoader()); // Make sure the interface is loaded from the parent class loader loader.excludeClass(TestService.class.getName()); loader.excludeClass(TestException.class.getName()); diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java index feaefe0e7f70..43373063622c 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java @@ -20,11 +20,11 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.tests.sample.beans.CountingTestBean; -import org.springframework.tests.sample.beans.IOther; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.tests.sample.beans.subpkg.DeepBean; +import org.springframework.beans.testfixture.beans.CountingTestBean; +import org.springframework.beans.testfixture.beans.IOther; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.beans.testfixture.beans.subpkg.DeepBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -57,7 +57,7 @@ void invocationOfMatchesMethodBlowsUpWhenNoTypePatternHasBeenSet() throws Except @Test void validPatternMatching() { - TypePatternClassFilter tpcf = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + TypePatternClassFilter tpcf = new TypePatternClassFilter("org.springframework.beans.testfixture.beans.*"); assertThat(tpcf.matches(TestBean.class)).as("Must match: in package").isTrue(); assertThat(tpcf.matches(ITestBean.class)).as("Must match: in package").isTrue(); @@ -70,7 +70,7 @@ void validPatternMatching() { @Test void subclassMatching() { - TypePatternClassFilter tpcf = new TypePatternClassFilter("org.springframework.tests.sample.beans.ITestBean+"); + TypePatternClassFilter tpcf = new TypePatternClassFilter("org.springframework.beans.testfixture.beans.ITestBean+"); assertThat(tpcf.matches(TestBean.class)).as("Must match: in package").isTrue(); assertThat(tpcf.matches(ITestBean.class)).as("Must match: in package").isTrue(); @@ -98,8 +98,8 @@ void andOrNotReplacement() { @Test void testEquals() { - TypePatternClassFilter filter1 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); - TypePatternClassFilter filter2 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + TypePatternClassFilter filter1 = new TypePatternClassFilter("org.springframework.beans.testfixture.beans.*"); + TypePatternClassFilter filter2 = new TypePatternClassFilter("org.springframework.beans.testfixture.beans.*"); TypePatternClassFilter filter3 = new TypePatternClassFilter("org.springframework.tests.*"); assertThat(filter1).isEqualTo(filter2); @@ -108,8 +108,8 @@ void testEquals() { @Test void testHashCode() { - TypePatternClassFilter filter1 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); - TypePatternClassFilter filter2 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + TypePatternClassFilter filter1 = new TypePatternClassFilter("org.springframework.beans.testfixture.beans.*"); + TypePatternClassFilter filter2 = new TypePatternClassFilter("org.springframework.beans.testfixture.beans.*"); TypePatternClassFilter filter3 = new TypePatternClassFilter("org.springframework.tests.*"); assertThat(filter1.hashCode()).isEqualTo(filter2.hashCode()); @@ -118,11 +118,11 @@ void testHashCode() { @Test void testToString() { - TypePatternClassFilter filter1 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); - TypePatternClassFilter filter2 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + TypePatternClassFilter filter1 = new TypePatternClassFilter("org.springframework.beans.testfixture.beans.*"); + TypePatternClassFilter filter2 = new TypePatternClassFilter("org.springframework.beans.testfixture.beans.*"); assertThat(filter1.toString()) - .isEqualTo("org.springframework.aop.aspectj.TypePatternClassFilter: org.springframework.tests.sample.beans.*"); + .isEqualTo("org.springframework.aop.aspectj.TypePatternClassFilter: org.springframework.beans.testfixture.beans.*"); assertThat(filter1.toString()).isEqualTo(filter2.toString()); } diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java index 0790a58f8adb..c7bad575019e 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; import java.rmi.RemoteException; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -50,11 +51,11 @@ import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.interceptor.ExposeInvocationInterceptor; import org.springframework.aop.support.AopUtils; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.OrderComparator; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -63,14 +64,16 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; /** - * Abstract tests for AspectJAdvisorFactory. - * See subclasses for tests of concrete factories. + * Abstract tests for {@link AspectJAdvisorFactory} implementations. + * + *

See subclasses for tests of concrete factories. * * @author Rod Johnson * @author Chris Beams * @author Phillip Webb + * @author Sam Brannen */ -public abstract class AbstractAspectJAdvisorFactoryTests { +abstract class AbstractAspectJAdvisorFactoryTests { /** * To be overridden by concrete test subclasses. @@ -80,7 +83,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests { @Test - public void testRejectsPerCflowAspect() { + void rejectsPerCflowAspect() { assertThatExceptionOfType(AopConfigException.class).isThrownBy(() -> getFixture().getAdvisors( new SingletonMetadataAwareAspectInstanceFactory(new PerCflowAspect(), "someBean"))) @@ -88,7 +91,7 @@ public void testRejectsPerCflowAspect() { } @Test - public void testRejectsPerCflowBelowAspect() { + void rejectsPerCflowBelowAspect() { assertThatExceptionOfType(AopConfigException.class).isThrownBy(() -> getFixture().getAdvisors( new SingletonMetadataAwareAspectInstanceFactory(new PerCflowBelowAspect(), "someBean"))) @@ -96,7 +99,7 @@ public void testRejectsPerCflowBelowAspect() { } @Test - public void testPerTargetAspect() throws SecurityException, NoSuchMethodException { + void perTargetAspect() throws SecurityException, NoSuchMethodException { TestBean target = new TestBean(); int realAge = 65; target.setAge(realAge); @@ -128,7 +131,7 @@ public void testPerTargetAspect() throws SecurityException, NoSuchMethodExceptio } @Test - public void testMultiplePerTargetAspects() throws SecurityException, NoSuchMethodException { + void multiplePerTargetAspects() throws SecurityException, NoSuchMethodException { TestBean target = new TestBean(); int realAge = 65; target.setAge(realAge); @@ -156,7 +159,7 @@ public void testMultiplePerTargetAspects() throws SecurityException, NoSuchMetho } @Test - public void testMultiplePerTargetAspectsWithOrderAnnotation() throws SecurityException, NoSuchMethodException { + void multiplePerTargetAspectsWithOrderAnnotation() throws SecurityException, NoSuchMethodException { TestBean target = new TestBean(); int realAge = 65; target.setAge(realAge); @@ -182,7 +185,7 @@ public void testMultiplePerTargetAspectsWithOrderAnnotation() throws SecurityExc } @Test - public void testPerThisAspect() throws SecurityException, NoSuchMethodException { + void perThisAspect() throws SecurityException, NoSuchMethodException { TestBean target = new TestBean(); int realAge = 65; target.setAge(realAge); @@ -218,7 +221,7 @@ public void testPerThisAspect() throws SecurityException, NoSuchMethodException } @Test - public void testPerTypeWithinAspect() throws SecurityException, NoSuchMethodException { + void perTypeWithinAspect() throws SecurityException, NoSuchMethodException { TestBean target = new TestBean(); int realAge = 65; target.setAge(realAge); @@ -259,22 +262,22 @@ public void testPerTypeWithinAspect() throws SecurityException, NoSuchMethodExce } @Test - public void testNamedPointcutAspectWithFQN() { - testNamedPointcuts(new NamedPointcutAspectWithFQN()); + void namedPointcutAspectWithFQN() { + namedPointcuts(new NamedPointcutAspectWithFQN()); } @Test - public void testNamedPointcutAspectWithoutFQN() { - testNamedPointcuts(new NamedPointcutAspectWithoutFQN()); + void namedPointcutAspectWithoutFQN() { + namedPointcuts(new NamedPointcutAspectWithoutFQN()); } @Test - public void testNamedPointcutFromAspectLibrary() { - testNamedPointcuts(new NamedPointcutAspectFromLibrary()); + void namedPointcutFromAspectLibrary() { + namedPointcuts(new NamedPointcutAspectFromLibrary()); } @Test - public void testNamedPointcutFromAspectLibraryWithBinding() { + void namedPointcutFromAspectLibraryWithBinding() { TestBean target = new TestBean(); ITestBean itb = (ITestBean) createProxy(target, getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory( @@ -285,7 +288,7 @@ public void testNamedPointcutFromAspectLibraryWithBinding() { assertThat(target.getAge()).isEqualTo(20); } - private void testNamedPointcuts(Object aspectInstance) { + private void namedPointcuts(Object aspectInstance) { TestBean target = new TestBean(); int realAge = 65; target.setAge(realAge); @@ -297,7 +300,7 @@ private void testNamedPointcuts(Object aspectInstance) { } @Test - public void testBindingWithSingleArg() { + void bindingWithSingleArg() { TestBean target = new TestBean(); ITestBean itb = (ITestBean) createProxy(target, getFixture().getAdvisors( @@ -309,7 +312,7 @@ public void testBindingWithSingleArg() { } @Test - public void testBindingWithMultipleArgsDifferentlyOrdered() { + void bindingWithMultipleArgsDifferentlyOrdered() { ManyValuedArgs target = new ManyValuedArgs(); ManyValuedArgs mva = (ManyValuedArgs) createProxy(target, getFixture().getAdvisors( @@ -329,7 +332,7 @@ public void testBindingWithMultipleArgsDifferentlyOrdered() { * In this case the introduction will be made. */ @Test - public void testIntroductionOnTargetNotImplementingInterface() { + void introductionOnTargetNotImplementingInterface() { NotLockable notLockableTarget = new NotLockable(); assertThat(notLockableTarget instanceof Lockable).isFalse(); NotLockable notLockable1 = (NotLockable) createProxy(notLockableTarget, @@ -358,7 +361,7 @@ public void testIntroductionOnTargetNotImplementingInterface() { } @Test - public void testIntroductionAdvisorExcludedFromTargetImplementingInterface() { + void introductionAdvisorExcludedFromTargetImplementingInterface() { assertThat(AopUtils.findAdvisorsThatCanApply( getFixture().getAdvisors( new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")), @@ -368,7 +371,7 @@ public void testIntroductionAdvisorExcludedFromTargetImplementingInterface() { } @Test - public void testIntroductionOnTargetImplementingInterface() { + void introductionOnTargetImplementingInterface() { CannotBeUnlocked target = new CannotBeUnlocked(); Lockable proxy = (Lockable) createProxy(target, // Ensure that we exclude @@ -388,7 +391,7 @@ public void testIntroductionOnTargetImplementingInterface() { } @Test - public void testIntroductionOnTargetExcludedByTypePattern() { + void introductionOnTargetExcludedByTypePattern() { LinkedList target = new LinkedList<>(); List proxy = (List) createProxy(target, AopUtils.findAdvisorsThatCanApply( @@ -400,7 +403,7 @@ public void testIntroductionOnTargetExcludedByTypePattern() { } @Test - public void testIntroductionBasedOnAnnotationMatch_SPR5307() { + void introductionBasedOnAnnotationMatch_SPR5307() { AnnotatedTarget target = new AnnotatedTargetImpl(); List advisors = getFixture().getAdvisors( new SingletonMetadataAwareAspectInstanceFactory(new MakeAnnotatedTypeModifiable(), "someBean")); @@ -414,7 +417,7 @@ public void testIntroductionBasedOnAnnotationMatch_SPR5307() { // TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed... @Test @Disabled - public void testIntroductionWithArgumentBinding() { + void introductionWithArgumentBinding() { TestBean target = new TestBean(); List advisors = getFixture().getAdvisors( @@ -448,11 +451,11 @@ public void testIntroductionWithArgumentBinding() { } @Test - public void testAspectMethodThrowsExceptionLegalOnSignature() { + void aspectMethodThrowsExceptionLegalOnSignature() { TestBean target = new TestBean(); UnsupportedOperationException expectedException = new UnsupportedOperationException(); List advisors = getFixture().getAdvisors( - new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException), "someBean")); + new SingletonMetadataAwareAspectInstanceFactory(new ExceptionThrowingAspect(expectedException), "someBean")); assertThat(advisors.size()).as("One advice method was found").isEqualTo(1); ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class); assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy( @@ -462,11 +465,11 @@ public void testAspectMethodThrowsExceptionLegalOnSignature() { // TODO document this behaviour. // Is it different AspectJ behaviour, at least for checked exceptions? @Test - public void testAspectMethodThrowsExceptionIllegalOnSignature() { + void aspectMethodThrowsExceptionIllegalOnSignature() { TestBean target = new TestBean(); RemoteException expectedException = new RemoteException(); List advisors = getFixture().getAdvisors( - new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException), "someBean")); + new SingletonMetadataAwareAspectInstanceFactory(new ExceptionThrowingAspect(expectedException), "someBean")); assertThat(advisors.size()).as("One advice method was found").isEqualTo(1); ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class); assertThatExceptionOfType(UndeclaredThrowableException.class).isThrownBy( @@ -491,7 +494,7 @@ protected Object createProxy(Object target, List advisors, Class... } @Test - public void testTwoAdvicesOnOneAspect() { + void twoAdvicesOnOneAspect() { TestBean target = new TestBean(); TwoAdviceAspect twoAdviceAspect = new TwoAdviceAspect(); List advisors = getFixture().getAdvisors( @@ -506,25 +509,23 @@ public void testTwoAdvicesOnOneAspect() { } @Test - public void testAfterAdviceTypes() throws Exception { - Echo target = new Echo(); - ExceptionHandling afterReturningAspect = new ExceptionHandling(); + void afterAdviceTypes() throws Exception { + InvocationTrackingAspect aspect = new InvocationTrackingAspect(); List advisors = getFixture().getAdvisors( - new SingletonMetadataAwareAspectInstanceFactory(afterReturningAspect, "someBean")); - Echo echo = (Echo) createProxy(target, advisors, Echo.class); - assertThat(afterReturningAspect.successCount).isEqualTo(0); - assertThat(echo.echo("")).isEqualTo(""); - assertThat(afterReturningAspect.successCount).isEqualTo(1); - assertThat(afterReturningAspect.failureCount).isEqualTo(0); - assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() -> - echo.echo(new FileNotFoundException())); - assertThat(afterReturningAspect.successCount).isEqualTo(1); - assertThat(afterReturningAspect.failureCount).isEqualTo(1); - assertThat(afterReturningAspect.afterCount).isEqualTo(afterReturningAspect.failureCount + afterReturningAspect.successCount); + new SingletonMetadataAwareAspectInstanceFactory(aspect, "exceptionHandlingAspect")); + Echo echo = (Echo) createProxy(new Echo(), advisors, Echo.class); + + assertThat(aspect.invocations).isEmpty(); + assertThat(echo.echo(42)).isEqualTo(42); + assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end"); + + aspect.invocations.clear(); + assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() -> echo.echo(new FileNotFoundException())); + assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end"); } @Test - public void testFailureWithoutExplicitDeclarePrecedence() { + void failureWithoutExplicitDeclarePrecedence() { TestBean target = new TestBean(); MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory( new NoDeclarePrecedenceShouldFail(), "someBean"); @@ -534,7 +535,7 @@ public void testFailureWithoutExplicitDeclarePrecedence() { } @Test - public void testDeclarePrecedenceNotSupported() { + void declarePrecedenceNotSupported() { TestBean target = new TestBean(); assertThatIllegalArgumentException().isThrownBy(() -> { MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory( @@ -545,28 +546,28 @@ public void testDeclarePrecedenceNotSupported() { @Aspect("percflow(execution(* *(..)))") - public static class PerCflowAspect { + static class PerCflowAspect { } @Aspect("percflowbelow(execution(* *(..)))") - public static class PerCflowBelowAspect { + static class PerCflowBelowAspect { } @Aspect("pertarget(execution(* *.getSpouse()))") @Order(10) - public static class PerTargetAspectWithOrderAnnotation10 { + static class PerTargetAspectWithOrderAnnotation10 { - public int count; + int count; @Around("execution(int *.getAge())") - public int returnCountAsAge() { + int returnCountAsAge() { return count++; } @Before("execution(void *.set*(int))") - public void countSetter() { + void countSetter() { ++count; } } @@ -574,34 +575,34 @@ public void countSetter() { @Aspect("pertarget(execution(* *.getSpouse()))") @Order(5) - public static class PerTargetAspectWithOrderAnnotation5 { + static class PerTargetAspectWithOrderAnnotation5 { - public int count; + int count; @Around("execution(int *.getAge())") - public int returnCountAsAge() { + int returnCountAsAge() { return count++; } @Before("execution(void *.set*(int))") - public void countSetter() { + void countSetter() { ++count; } } - @Aspect("pertypewithin(org.springframework.tests.sample.beans.IOther+)") - public static class PerTypeWithinAspect { + @Aspect("pertypewithin(org.springframework.beans.testfixture.beans.IOther+)") + static class PerTypeWithinAspect { - public int count; + int count; @Around("execution(int *.getAge())") - public int returnCountAsAge() { + int returnCountAsAge() { return count++; } @Before("execution(void *.*(..))") - public void countAnythingVoid() { + void countAnythingVoid() { ++count; } } @@ -611,7 +612,7 @@ private class PerTypeWithinAspectInstanceFactory implements MetadataAwareAspectI private int count; - public int getInstantiationCount() { + int getInstantiationCount() { return this.count; } @@ -644,97 +645,96 @@ public int getOrder() { @Aspect - public static class NamedPointcutAspectWithFQN { + static class NamedPointcutAspectWithFQN { @SuppressWarnings("unused") private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean(); @Pointcut("execution(* getAge())") - public void getAge() { + void getAge() { } @Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.NamedPointcutAspectWithFQN.getAge()") - public int changeReturnValue(ProceedingJoinPoint pjp) { + int changeReturnValue(ProceedingJoinPoint pjp) { return -1; } } @Aspect - public static class NamedPointcutAspectWithoutFQN { + static class NamedPointcutAspectWithoutFQN { @Pointcut("execution(* getAge())") - public void getAge() { + void getAge() { } @Around("getAge()") - public int changeReturnValue(ProceedingJoinPoint pjp) { + int changeReturnValue(ProceedingJoinPoint pjp) { return -1; } } @Aspect - public static class NamedPointcutAspectFromLibrary { + static class NamedPointcutAspectFromLibrary { @Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.propertyAccess()") - public int changeReturnType(ProceedingJoinPoint pjp) { + int changeReturnType(ProceedingJoinPoint pjp) { return -1; } @Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x") - public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable { + void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable { pjp.proceed(new Object[] {x*2}); } } @Aspect - public static class Library { + static class Library { @Pointcut("execution(!void get*())") - public void propertyAccess() {} + void propertyAccess() {} @Pointcut("execution(* *(..)) && args(i)") - public void integerArgOperation(int i) {} - + void integerArgOperation(int i) {} } @Aspect - public static class NamedPointcutAspectFromLibraryWithBinding { + static class NamedPointcutAspectFromLibraryWithBinding { @Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x") - public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable { + void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable { pjp.proceed(new Object[] {x*2}); } } @Aspect - public static class BindingAspectWithSingleArg { + static class BindingAspectWithSingleArg { @Pointcut(value="args(a)", argNames="a") - public void setAge(int a) {} + void setAge(int a) {} @Around(value="setAge(age)",argNames="age") // @ArgNames({"age"}) // AMC needs more work here? ignoring pjp arg... ok?? // argNames should be supported in Around as it is in Pointcut - public void changeReturnType(ProceedingJoinPoint pjp, int age) throws Throwable { + void changeReturnType(ProceedingJoinPoint pjp, int age) throws Throwable { pjp.proceed(new Object[] {age*2}); } } @Aspect - public static class ManyValuedArgs { + static class ManyValuedArgs { - public String mungeArgs(String a, int b, int c, String d, StringBuffer e) { + String mungeArgs(String a, int b, int c, String d, StringBuffer e) { return a + b + c + d + e; } @Around(value="execution(String mungeArgs(..)) && args(a, b, c, d, e)", argNames="b,c,d,e,a") - public String reverseAdvice(ProceedingJoinPoint pjp, int b, int c, String d, StringBuffer e, String a) throws Throwable { + String reverseAdvice(ProceedingJoinPoint pjp, int b, int c, String d, StringBuffer e, String a) throws Throwable { assertThat(pjp.proceed()).isEqualTo(a + b+ c+ d+ e); return a + b + c + d + e; } @@ -742,24 +742,24 @@ public String reverseAdvice(ProceedingJoinPoint pjp, int b, int c, String d, Str @Aspect - public static class ExceptionAspect { + static class ExceptionThrowingAspect { private final Exception ex; - public ExceptionAspect(Exception ex) { + ExceptionThrowingAspect(Exception ex) { this.ex = ex; } @Before("execution(* getAge())") - public void throwException() throws Exception { + void throwException() throws Exception { throw ex; } } - public static class Echo { + static class Echo { - public Object echo(Object o) throws Exception { + Object echo(Object o) throws Exception { if (o instanceof Exception) { throw (Exception) o; } @@ -769,45 +769,62 @@ public Object echo(Object o) throws Exception { @Aspect - public static class ExceptionHandling { + private static class InvocationTrackingAspect { + + List invocations = new ArrayList<>(); + - public int successCount; + @Pointcut("execution(* echo(*))") + void echo() { + } - public int failureCount; + @Around("echo()") + Object around(ProceedingJoinPoint joinPoint) throws Throwable { + invocations.add("around - start"); + try { + return joinPoint.proceed(); + } + finally { + invocations.add("around - end"); + } + } - public int afterCount; + @Before("echo()") + void before() { + invocations.add("before"); + } - @AfterReturning("execution(* echo(*))") - public void succeeded() { - ++successCount; + @AfterReturning("echo()") + void afterReturning() { + invocations.add("after returning"); } - @AfterThrowing("execution(* echo(*))") - public void failed() { - ++failureCount; + @AfterThrowing("echo()") + void afterThrowing() { + invocations.add("after throwing"); } - @After("execution(* echo(*))") - public void invoked() { - ++afterCount; + @After("echo()") + void after() { + invocations.add("after"); } } @Aspect - public static class NoDeclarePrecedenceShouldFail { + static class NoDeclarePrecedenceShouldFail { @Pointcut("execution(int *.getAge())") - public void getAge() { + void getAge() { } @Before("getAge()") - public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() { + void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() { throw new IllegalStateException(); } @Around("getAge()") - public int preventExecution(ProceedingJoinPoint pjp) { + int preventExecution(ProceedingJoinPoint pjp) { return 666; } } @@ -815,19 +832,19 @@ public int preventExecution(ProceedingJoinPoint pjp) { @Aspect @DeclarePrecedence("test..*") - public static class DeclarePrecedenceShouldSucceed { + static class DeclarePrecedenceShouldSucceed { @Pointcut("execution(int *.getAge())") - public void getAge() { + void getAge() { } @Before("getAge()") - public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() { + void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() { throw new IllegalStateException(); } @Around("getAge()") - public int preventExecution(ProceedingJoinPoint pjp) { + int preventExecution(ProceedingJoinPoint pjp) { return 666; } } @@ -845,12 +862,12 @@ public int preventExecution(ProceedingJoinPoint pjp) { @Aspect abstract class AbstractMakeModifiable { - public interface MutableModifiable extends Modifiable { + interface MutableModifiable extends Modifiable { void markDirty(); } - public static class ModifiableImpl implements MutableModifiable { + static class ModifiableImpl implements MutableModifiable { private boolean modified; @@ -871,7 +888,7 @@ public void markDirty() { } @Before(value="execution(void set*(*)) && this(modifiable) && args(newValue)", argNames="modifiable,newValue") - public void recordModificationIfSetterArgumentDiffersFromOldValue( + void recordModificationIfSetterArgumentDiffersFromOldValue( JoinPoint jp, MutableModifiable mixin, Object newValue) { /* @@ -931,9 +948,9 @@ private Method getGetterFromSetter(Method setter) { @Aspect class MakeITestBeanModifiable extends AbstractMakeModifiable { - @DeclareParents(value = "org.springframework.tests.sample.beans.ITestBean+", + @DeclareParents(value = "org.springframework.beans.testfixture.beans.ITestBean+", defaultImpl=ModifiableImpl.class) - public static MutableModifiable mixin; + static MutableModifiable mixin; } @@ -948,7 +965,7 @@ class MakeAnnotatedTypeModifiable extends AbstractMakeModifiable { @DeclareParents(value = "(@org.springframework.aop.aspectj.annotation.Measured *)", defaultImpl = DefaultLockable.class) - public static Lockable mixin; + static Lockable mixin; } @@ -960,10 +977,10 @@ class MakeAnnotatedTypeModifiable extends AbstractMakeModifiable { class MakeLockable { @DeclareParents(value = "org.springframework..*", defaultImpl = DefaultLockable.class) - public static Lockable mixin; + static Lockable mixin; @Before(value="execution(void set*(*)) && this(mixin)", argNames="mixin") - public void checkNotLocked( Lockable mixin) { + void checkNotLocked( Lockable mixin) { // Can also obtain the mixin (this) this way //Lockable mixin = (Lockable) jp.getThis(); if (mixin.locked()) { @@ -1032,11 +1049,11 @@ class NotLockable { private int intValue; - public int getIntValue() { + int getIntValue() { return intValue; } - public void setIntValue(int intValue) { + void setIntValue(int intValue) { this.intValue = intValue; } @@ -1046,19 +1063,19 @@ public void setIntValue(int intValue) { @Aspect("perthis(execution(* *.getSpouse()))") class PerThisAspect { - public int count; + int count; // Just to check that this doesn't cause problems with introduction processing @SuppressWarnings("unused") private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean(); @Around("execution(int *.getAge())") - public int returnCountAsAge() { + int returnCountAsAge() { return count++; } @Before("execution(void *.set*(int))") - public void countSetter() { + void countSetter() { ++count; } diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/ArgumentBindingTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/ArgumentBindingTests.java index e0806be6f060..835f4a4f95c3 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/ArgumentBindingTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/ArgumentBindingTests.java @@ -27,8 +27,8 @@ import org.junit.jupiter.api.Test; import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java index bbc816b3289a..806f30587bbe 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,9 @@ import org.springframework.aop.Pointcut; import org.springframework.aop.aspectj.AspectJExpressionPointcut; import org.springframework.aop.aspectj.AspectJExpressionPointcutTests; +import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.ExceptionThrowingAspect; import org.springframework.aop.framework.AopConfigException; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -44,7 +45,7 @@ public void testSingleton() throws SecurityException, NoSuchMethodException { InstantiationModelAwarePointcutAdvisorImpl ajpa = new InstantiationModelAwarePointcutAdvisorImpl( ajexp, TestBean.class.getMethod("getAge"), af, - new SingletonMetadataAwareAspectInstanceFactory(new AbstractAspectJAdvisorFactoryTests.ExceptionAspect(null), "someBean"), + new SingletonMetadataAwareAspectInstanceFactory(new ExceptionThrowingAspect(null), "someBean"), 1, "someBean"); assertThat(ajpa.getAspectMetadata().getPerClausePointcut()).isSameAs(Pointcut.TRUE); diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectMetadataTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectMetadataTests.java index 45c93c628d26..637baa2450a8 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectMetadataTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectMetadataTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,8 @@ import test.aop.PerTargetAspect; import org.springframework.aop.Pointcut; -import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.ExceptionAspect; +import org.springframework.aop.aspectj.AspectJExpressionPointcut; +import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.ExceptionThrowingAspect; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -30,36 +31,43 @@ * @since 2.0 * @author Rod Johnson * @author Chris Beams + * @author Sam Brannen */ -public class AspectMetadataTests { +class AspectMetadataTests { @Test - public void testNotAnAspect() { - assertThatIllegalArgumentException().isThrownBy(() -> - new AspectMetadata(String.class,"someBean")); + void notAnAspect() { + assertThatIllegalArgumentException().isThrownBy(() -> new AspectMetadata(String.class, "someBean")); } @Test - public void testSingletonAspect() { - AspectMetadata am = new AspectMetadata(ExceptionAspect.class,"someBean"); + void singletonAspect() { + AspectMetadata am = new AspectMetadata(ExceptionThrowingAspect.class, "someBean"); assertThat(am.isPerThisOrPerTarget()).isFalse(); assertThat(am.getPerClausePointcut()).isSameAs(Pointcut.TRUE); assertThat(am.getAjType().getPerClause().getKind()).isEqualTo(PerClauseKind.SINGLETON); } @Test - public void testPerTargetAspect() { - AspectMetadata am = new AspectMetadata(PerTargetAspect.class,"someBean"); + void perTargetAspect() { + AspectMetadata am = new AspectMetadata(PerTargetAspect.class, "someBean"); assertThat(am.isPerThisOrPerTarget()).isTrue(); assertThat(am.getPerClausePointcut()).isNotSameAs(Pointcut.TRUE); assertThat(am.getAjType().getPerClause().getKind()).isEqualTo(PerClauseKind.PERTARGET); + assertThat(am.getPerClausePointcut()).isInstanceOf(AspectJExpressionPointcut.class); + assertThat(((AspectJExpressionPointcut) am.getPerClausePointcut()).getExpression()) + .isEqualTo("execution(* *.getSpouse())"); } @Test - public void testPerThisAspect() { - AspectMetadata am = new AspectMetadata(PerThisAspect.class,"someBean"); + void perThisAspect() { + AspectMetadata am = new AspectMetadata(PerThisAspect.class, "someBean"); assertThat(am.isPerThisOrPerTarget()).isTrue(); assertThat(am.getPerClausePointcut()).isNotSameAs(Pointcut.TRUE); assertThat(am.getAjType().getPerClause().getKind()).isEqualTo(PerClauseKind.PERTHIS); + assertThat(am.getPerClausePointcut()).isInstanceOf(AspectJExpressionPointcut.class); + assertThat(((AspectJExpressionPointcut) am.getPerClausePointcut()).getExpression()) + .isEqualTo("execution(* *.getSpouse())"); } + } diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java index 0c4d6ff1d8d1..d048e6e0d18c 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java @@ -26,7 +26,7 @@ import org.junit.jupiter.api.Test; import test.aop.PerThisAspect; -import org.springframework.util.SerializationTestUtils; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactoryTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactoryTests.java index 3eac9fac5225..d649ea019642 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactoryTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,13 +17,14 @@ package org.springframework.aop.aspectj.annotation; /** - * Tests for ReflectiveAtAspectJAdvisorFactory. - * Tests are inherited: we only set the test fixture here. + * Tests for {@link ReflectiveAspectJAdvisorFactory}. + * + *

Tests are inherited: we only set the test fixture here. * * @author Rod Johnson * @since 2.0 */ -public class ReflectiveAspectJAdvisorFactoryTests extends AbstractAspectJAdvisorFactoryTests { +class ReflectiveAspectJAdvisorFactoryTests extends AbstractAspectJAdvisorFactoryTests { @Override protected AspectJAdvisorFactory getFixture() { diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJNamespaceHandlerTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJNamespaceHandlerTests.java index b2b1323b4fd9..a6ecf37304de 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJNamespaceHandlerTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJNamespaceHandlerTests.java @@ -29,7 +29,7 @@ import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.beans.factory.xml.XmlReaderContext; -import org.springframework.tests.beans.CollectingReaderEventListener; +import org.springframework.beans.testfixture.beans.CollectingReaderEventListener; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/config/AopNamespaceHandlerEventTests.java b/spring-aop/src/test/java/org/springframework/aop/config/AopNamespaceHandlerEventTests.java index c31d5a396d04..d4c774424d04 100644 --- a/spring-aop/src/test/java/org/springframework/aop/config/AopNamespaceHandlerEventTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/config/AopNamespaceHandlerEventTests.java @@ -29,11 +29,11 @@ import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.testfixture.beans.CollectingReaderEventListener; import org.springframework.core.io.Resource; -import org.springframework.tests.beans.CollectingReaderEventListener; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Rob Harrop diff --git a/spring-aop/src/test/java/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests.java b/spring-aop/src/test/java/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests.java index 7b07a2f793ee..6a01b03ad7b2 100644 --- a/spring-aop/src/test/java/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests.java @@ -24,7 +24,7 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Mark Fisher diff --git a/spring-aop/src/test/java/org/springframework/aop/config/TopLevelAopTagTests.java b/spring-aop/src/test/java/org/springframework/aop/config/TopLevelAopTagTests.java index 95732b92a1d7..f1ab7f273db9 100644 --- a/spring-aop/src/test/java/org/springframework/aop/config/TopLevelAopTagTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/config/TopLevelAopTagTests.java @@ -22,7 +22,7 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * Tests that the <aop:config/> element can be used as a top level element. diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java index f2f9c624424e..c8475794f337 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java @@ -23,8 +23,8 @@ import org.junit.jupiter.api.Test; import org.springframework.aop.SpringProxy; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/IntroductionBenchmarkTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/IntroductionBenchmarkTests.java index 50092ca733b7..d3defccfb429 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/IntroductionBenchmarkTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/IntroductionBenchmarkTests.java @@ -19,8 +19,8 @@ import org.junit.jupiter.api.Test; import org.springframework.aop.support.DelegatingIntroductionInterceptor; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.util.StopWatch; /** diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/MethodInvocationTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/MethodInvocationTests.java index 9de8bd658c15..91091035aac7 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/MethodInvocationTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/MethodInvocationTests.java @@ -23,7 +23,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.junit.jupiter.api.Test; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/PrototypeTargetTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/PrototypeTargetTests.java index 6174c02a0c19..d58a9b594a16 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/PrototypeTargetTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/PrototypeTargetTests.java @@ -25,7 +25,7 @@ import org.springframework.core.io.Resource; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Juergen Hoeller diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java index 7372468f9c3b..78cfdcde54a1 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,15 +33,15 @@ import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.DefaultIntroductionAdvisor; import org.springframework.aop.support.DefaultPointcutAdvisor; -import org.springframework.aop.support.DelegatingIntroductionInterceptor; +import org.springframework.aop.testfixture.advice.CountingBeforeAdvice; +import org.springframework.aop.testfixture.interceptor.NopInterceptor; +import org.springframework.aop.testfixture.interceptor.TimestampIntroductionInterceptor; +import org.springframework.beans.testfixture.beans.IOther; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; -import org.springframework.tests.TimeStamped; -import org.springframework.tests.aop.advice.CountingBeforeAdvice; -import org.springframework.tests.aop.interceptor.NopInterceptor; -import org.springframework.tests.sample.beans.IOther; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.core.testfixture.TimeStamped; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -183,7 +183,7 @@ public void testAddRepeatedInterface() { } @Test - public void testGetsAllInterfaces() throws Exception { + public void testGetsAllInterfaces() { // Extend to get new interface class TestBeanSubclass extends TestBean implements Comparable { @Override @@ -371,30 +371,6 @@ public void testInterceptorWithoutJoinpoint() { } - @SuppressWarnings("serial") - private static class TimestampIntroductionInterceptor extends DelegatingIntroductionInterceptor - implements TimeStamped { - - private long ts; - - public TimestampIntroductionInterceptor() { - } - - public TimestampIntroductionInterceptor(long ts) { - this.ts = ts; - } - - public void setTime(long ts) { - this.ts = ts; - } - - @Override - public long getTimeStamp() { - return ts; - } - } - - @Order(2) public static class A implements Runnable { diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptorTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptorTests.java index a836bcc00314..2c1060274e74 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptorTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptorTests.java @@ -17,16 +17,13 @@ package org.springframework.aop.framework.adapter; import java.io.FileNotFoundException; -import java.io.IOException; -import java.lang.reflect.Method; import java.rmi.ConnectException; import java.rmi.RemoteException; import org.aopalliance.intercept.MethodInvocation; import org.junit.jupiter.api.Test; -import org.springframework.aop.ThrowsAdvice; -import org.springframework.tests.aop.advice.MethodCounter; +import org.springframework.aop.testfixture.advice.MyThrowsHandler; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -128,23 +125,4 @@ public void afterThrowing(RemoteException ex) throws Throwable { assertThat(th.getCalls("remoteException")).isEqualTo(1); } - - @SuppressWarnings("serial") - static class MyThrowsHandler extends MethodCounter implements ThrowsAdvice { - - // Full method signature - public void afterThrowing(Method m, Object[] args, Object target, IOException ex) { - count("ioException"); - } - - public void afterThrowing(RemoteException ex) throws Throwable { - count("remoteException"); - } - - /** Not valid, wrong number of arguments */ - public void afterThrowing(Method m, Exception ex) throws Throwable { - throw new UnsupportedOperationException("Shouldn't be called"); - } - } - } diff --git a/spring-aop/src/test/java/org/springframework/aop/interceptor/ConcurrencyThrottleInterceptorTests.java b/spring-aop/src/test/java/org/springframework/aop/interceptor/ConcurrencyThrottleInterceptorTests.java index 9477df4ca017..43e4a93ded88 100644 --- a/spring-aop/src/test/java/org/springframework/aop/interceptor/ConcurrencyThrottleInterceptorTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/interceptor/ConcurrencyThrottleInterceptorTests.java @@ -22,10 +22,10 @@ import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.ProxyFactory; -import org.springframework.tests.sample.beans.DerivedTestBean; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.util.SerializationTestUtils; +import org.springframework.beans.testfixture.beans.DerivedTestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/interceptor/ExposeBeanNameAdvisorsTests.java b/spring-aop/src/test/java/org/springframework/aop/interceptor/ExposeBeanNameAdvisorsTests.java index ccb4d526313b..9bd43d1aef3f 100644 --- a/spring-aop/src/test/java/org/springframework/aop/interceptor/ExposeBeanNameAdvisorsTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/interceptor/ExposeBeanNameAdvisorsTests.java @@ -20,8 +20,8 @@ import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.NamedBean; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests.java b/spring-aop/src/test/java/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests.java index 76b682bf093e..40f266f64710 100644 --- a/spring-aop/src/test/java/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests.java @@ -21,11 +21,11 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * Non-XML tests are in AbstractAopProxyTests diff --git a/spring-aop/src/test/java/org/springframework/aop/scope/ScopedProxyAutowireTests.java b/spring-aop/src/test/java/org/springframework/aop/scope/ScopedProxyAutowireTests.java index 42f32fa1eb02..a746532495b0 100644 --- a/spring-aop/src/test/java/org/springframework/aop/scope/ScopedProxyAutowireTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/scope/ScopedProxyAutowireTests.java @@ -24,7 +24,7 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Mark Fisher diff --git a/spring-aop/src/test/java/org/springframework/aop/support/AbstractRegexpMethodPointcutTests.java b/spring-aop/src/test/java/org/springframework/aop/support/AbstractRegexpMethodPointcutTests.java index f13ebf47fea3..aa8cd95dc9aa 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/AbstractRegexpMethodPointcutTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/AbstractRegexpMethodPointcutTests.java @@ -21,8 +21,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.util.SerializationTestUtils; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/support/AopUtilsTests.java b/spring-aop/src/test/java/org/springframework/aop/support/AopUtilsTests.java index 63778647debc..dc5437e6cd67 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/AopUtilsTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/AopUtilsTests.java @@ -25,10 +25,10 @@ import org.springframework.aop.Pointcut; import org.springframework.aop.interceptor.ExposeInvocationInterceptor; import org.springframework.aop.target.EmptyTargetSource; +import org.springframework.aop.testfixture.interceptor.NopInterceptor; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.core.testfixture.io.SerializationTestUtils; import org.springframework.lang.Nullable; -import org.springframework.tests.aop.interceptor.NopInterceptor; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.util.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java b/spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java index 00ea9213e536..db83a9424df1 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java @@ -19,9 +19,9 @@ import org.junit.jupiter.api.Test; import org.springframework.aop.ClassFilter; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.NestedRuntimeException; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/support/ClassUtilsTests.java b/spring-aop/src/test/java/org/springframework/aop/support/ClassUtilsTests.java index 39139bbbd02e..6eac64eb77b8 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/ClassUtilsTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/ClassUtilsTests.java @@ -18,7 +18,7 @@ import org.junit.jupiter.api.Test; import org.springframework.aop.framework.ProxyFactory; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.util.ClassUtils; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/support/ComposablePointcutTests.java b/spring-aop/src/test/java/org/springframework/aop/support/ComposablePointcutTests.java index c4400b3371b9..87b408222c2b 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/ComposablePointcutTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/ComposablePointcutTests.java @@ -23,9 +23,9 @@ import org.springframework.aop.ClassFilter; import org.springframework.aop.MethodMatcher; import org.springframework.aop.Pointcut; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.NestedRuntimeException; import org.springframework.lang.Nullable; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java b/spring-aop/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java index 72623dbf6559..f86c6e7ca9f1 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java @@ -20,9 +20,9 @@ import org.springframework.aop.Pointcut; import org.springframework.aop.framework.ProxyFactory; -import org.springframework.tests.aop.interceptor.NopInterceptor; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.aop.testfixture.interceptor.NopInterceptor; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/support/DelegatingIntroductionInterceptorTests.java b/spring-aop/src/test/java/org/springframework/aop/support/DelegatingIntroductionInterceptorTests.java index a165be41a406..4325e582704f 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/DelegatingIntroductionInterceptorTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/DelegatingIntroductionInterceptorTests.java @@ -24,15 +24,15 @@ import org.springframework.aop.IntroductionAdvisor; import org.springframework.aop.IntroductionInterceptor; import org.springframework.aop.framework.ProxyFactory; -import org.springframework.tests.TimeStamped; -import org.springframework.tests.aop.interceptor.SerializableNopInterceptor; -import org.springframework.tests.sample.beans.INestedTestBean; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.NestedTestBean; -import org.springframework.tests.sample.beans.Person; -import org.springframework.tests.sample.beans.SerializablePerson; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.util.SerializationTestUtils; +import org.springframework.aop.testfixture.interceptor.SerializableNopInterceptor; +import org.springframework.beans.testfixture.beans.INestedTestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.NestedTestBean; +import org.springframework.beans.testfixture.beans.Person; +import org.springframework.beans.testfixture.beans.SerializablePerson; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.core.testfixture.TimeStamped; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; diff --git a/spring-aop/src/test/java/org/springframework/aop/support/MethodMatchersTests.java b/spring-aop/src/test/java/org/springframework/aop/support/MethodMatchersTests.java index f860ef72d4eb..55a2d7cabb57 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/MethodMatchersTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/MethodMatchersTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,11 +21,11 @@ import org.junit.jupiter.api.Test; import org.springframework.aop.MethodMatcher; +import org.springframework.beans.testfixture.beans.IOther; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.core.testfixture.io.SerializationTestUtils; import org.springframework.lang.Nullable; -import org.springframework.tests.sample.beans.IOther; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.util.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -83,12 +83,12 @@ public void testDynamicAndStaticMethodMatcherIntersection() throws Exception { MethodMatcher intersection = MethodMatchers.intersection(mm1, mm2); assertThat(intersection.isRuntime()).as("Intersection is a dynamic matcher").isTrue(); assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class)).as("2Matched setAge method").isTrue(); - assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class, new Integer(5))).as("3Matched setAge method").isTrue(); + assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class, 5)).as("3Matched setAge method").isTrue(); // Knock out dynamic part intersection = MethodMatchers.intersection(intersection, new TestDynamicMethodMatcherWhichDoesNotMatch()); assertThat(intersection.isRuntime()).as("Intersection is a dynamic matcher").isTrue(); assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class)).as("2Matched setAge method").isTrue(); - assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class, new Integer(5))).as("3 - not Matched setAge method").isFalse(); + assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class, 5)).as("3 - not Matched setAge method").isFalse(); } @Test diff --git a/spring-aop/src/test/java/org/springframework/aop/support/NameMatchMethodPointcutTests.java b/spring-aop/src/test/java/org/springframework/aop/support/NameMatchMethodPointcutTests.java index 91517e6831c1..98f7ca29a97e 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/NameMatchMethodPointcutTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/NameMatchMethodPointcutTests.java @@ -21,11 +21,11 @@ import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.ProxyFactory; -import org.springframework.tests.aop.interceptor.NopInterceptor; -import org.springframework.tests.aop.interceptor.SerializableNopInterceptor; -import org.springframework.tests.sample.beans.Person; -import org.springframework.tests.sample.beans.SerializablePerson; -import org.springframework.util.SerializationTestUtils; +import org.springframework.aop.testfixture.interceptor.NopInterceptor; +import org.springframework.aop.testfixture.interceptor.SerializableNopInterceptor; +import org.springframework.beans.testfixture.beans.Person; +import org.springframework.beans.testfixture.beans.SerializablePerson; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/support/PointcutsTests.java b/spring-aop/src/test/java/org/springframework/aop/support/PointcutsTests.java index 599354821a02..9a6f05e10171 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/PointcutsTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/PointcutsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,8 @@ import org.springframework.aop.ClassFilter; import org.springframework.aop.Pointcut; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.lang.Nullable; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; @@ -121,20 +121,20 @@ public boolean matches(Method m, @Nullable Class targetClass) { @Test public void testTrue() { - assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue(); + assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue(); assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_GET_AGE, TestBean.class)).isTrue(); assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_ABSQUATULATE, TestBean.class)).isTrue(); - assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue(); + assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue(); assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_GET_AGE, TestBean.class)).isTrue(); assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_ABSQUATULATE, TestBean.class)).isTrue(); } @Test public void testMatches() { - assertThat(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue(); + assertThat(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue(); assertThat(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_GET_AGE, TestBean.class)).isFalse(); assertThat(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse(); - assertThat(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse(); + assertThat(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse(); assertThat(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_GET_AGE, TestBean.class)).isTrue(); assertThat(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse(); } @@ -145,7 +145,7 @@ public void testMatches() { @Test public void testUnionOfSettersAndGetters() { Pointcut union = Pointcuts.union(allClassGetterPointcut, allClassSetterPointcut); - assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue(); + assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue(); assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class)).isTrue(); assertThat(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse(); } @@ -153,7 +153,7 @@ public void testUnionOfSettersAndGetters() { @Test public void testUnionOfSpecificGetters() { Pointcut union = Pointcuts.union(allClassGetAgePointcut, allClassGetNamePointcut); - assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse(); + assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse(); assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class)).isTrue(); assertThat(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_NAME, TestBean.class)).isFalse(); assertThat(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class)).isTrue(); @@ -161,13 +161,13 @@ public void testUnionOfSpecificGetters() { // Union with all setters union = Pointcuts.union(union, allClassSetterPointcut); - assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue(); + assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue(); assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class)).isTrue(); assertThat(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_NAME, TestBean.class)).isFalse(); assertThat(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class)).isTrue(); assertThat(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse(); - assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue(); + assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue(); } /** @@ -176,16 +176,16 @@ public void testUnionOfSpecificGetters() { */ @Test public void testUnionOfAllSettersAndSubclassSetters() { - assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse(); - assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, MyTestBean.class, new Integer(6))).isTrue(); + assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse(); + assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, MyTestBean.class, 6)).isTrue(); assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_GET_AGE, TestBean.class)).isFalse(); Pointcut union = Pointcuts.union(myTestBeanSetterPointcut, allClassGetterPointcut); assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class)).isTrue(); assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, MyTestBean.class)).isTrue(); // Still doesn't match superclass setter - assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, MyTestBean.class, new Integer(6))).isTrue(); - assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse(); + assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, MyTestBean.class, 6)).isTrue(); + assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse(); } /** @@ -241,7 +241,7 @@ public void testIntersectionOfSpecificGettersAndSubclassGetters() { @Test public void testSimpleIntersection() { Pointcut intersection = Pointcuts.intersection(allClassGetterPointcut, allClassSetterPointcut); - assertThat(Pointcuts.matches(intersection, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse(); + assertThat(Pointcuts.matches(intersection, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse(); assertThat(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, TestBean.class)).isFalse(); assertThat(Pointcuts.matches(intersection, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse(); } diff --git a/spring-aop/src/test/java/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests.java b/spring-aop/src/test/java/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests.java index da9699a305b3..de3886ef85ee 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests.java @@ -19,18 +19,18 @@ import org.junit.jupiter.api.Test; import org.springframework.aop.framework.Advised; +import org.springframework.aop.testfixture.interceptor.NopInterceptor; +import org.springframework.aop.testfixture.interceptor.SerializableNopInterceptor; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.Person; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.Resource; -import org.springframework.tests.aop.interceptor.NopInterceptor; -import org.springframework.tests.aop.interceptor.SerializableNopInterceptor; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.Person; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.util.SerializationTestUtils; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Rod Johnson diff --git a/spring-aop/src/test/java/org/springframework/aop/support/RootClassFilterTests.java b/spring-aop/src/test/java/org/springframework/aop/support/RootClassFilterTests.java index 0c132f327e3b..e09344b35bc8 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/RootClassFilterTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/RootClassFilterTests.java @@ -19,7 +19,7 @@ import org.junit.jupiter.api.Test; import org.springframework.aop.ClassFilter; -import org.springframework.tests.sample.beans.ITestBean; +import org.springframework.beans.testfixture.beans.ITestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aop/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceProxyTests.java b/spring-aop/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceProxyTests.java index 31afac2e099c..6637815d058e 100644 --- a/spring-aop/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceProxyTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/target/CommonsPool2TargetSourceProxyTests.java @@ -21,11 +21,11 @@ import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.testfixture.beans.ITestBean; import org.springframework.core.io.Resource; -import org.springframework.tests.sample.beans.ITestBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Stephane Nicoll diff --git a/spring-aop/src/test/java/org/springframework/aop/target/HotSwappableTargetSourceTests.java b/spring-aop/src/test/java/org/springframework/aop/target/HotSwappableTargetSourceTests.java index ef7bea56dae9..a3354a5587f7 100644 --- a/spring-aop/src/test/java/org/springframework/aop/target/HotSwappableTargetSourceTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/target/HotSwappableTargetSourceTests.java @@ -23,17 +23,17 @@ import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.aop.testfixture.interceptor.SerializableNopInterceptor; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.tests.aop.interceptor.SerializableNopInterceptor; -import org.springframework.tests.sample.beans.Person; -import org.springframework.tests.sample.beans.SerializablePerson; -import org.springframework.tests.sample.beans.SideEffectBean; -import org.springframework.util.SerializationTestUtils; +import org.springframework.beans.testfixture.beans.Person; +import org.springframework.beans.testfixture.beans.SerializablePerson; +import org.springframework.beans.testfixture.beans.SideEffectBean; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Rod Johnson diff --git a/spring-aop/src/test/java/org/springframework/aop/target/LazyInitTargetSourceTests.java b/spring-aop/src/test/java/org/springframework/aop/target/LazyInitTargetSourceTests.java index 0efaa5165e6f..6c38a0f04fc2 100644 --- a/spring-aop/src/test/java/org/springframework/aop/target/LazyInitTargetSourceTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/target/LazyInitTargetSourceTests.java @@ -22,11 +22,11 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.testfixture.beans.ITestBean; import org.springframework.core.io.Resource; -import org.springframework.tests.sample.beans.ITestBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Juergen Hoeller diff --git a/spring-aop/src/test/java/org/springframework/aop/target/PrototypeBasedTargetSourceTests.java b/spring-aop/src/test/java/org/springframework/aop/target/PrototypeBasedTargetSourceTests.java index f051925ad3c6..3a84193d50f1 100644 --- a/spring-aop/src/test/java/org/springframework/aop/target/PrototypeBasedTargetSourceTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/target/PrototypeBasedTargetSourceTests.java @@ -20,11 +20,12 @@ import org.springframework.aop.TargetSource; import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.tests.sample.beans.SerializablePerson; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.util.SerializationTestUtils; +import org.springframework.beans.testfixture.beans.SerializablePerson; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -47,7 +48,7 @@ public void testSerializability() throws Exception { MutablePropertyValues pvs = new MutablePropertyValues(); RootBeanDefinition bd = new RootBeanDefinition(SerializablePerson.class); bd.setPropertyValues(pvs); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); bf.registerBeanDefinition("ts", tsBd); diff --git a/spring-aop/src/test/java/org/springframework/aop/target/PrototypeTargetSourceTests.java b/spring-aop/src/test/java/org/springframework/aop/target/PrototypeTargetSourceTests.java index edcf3379a7cf..7871e1072d18 100644 --- a/spring-aop/src/test/java/org/springframework/aop/target/PrototypeTargetSourceTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/target/PrototypeTargetSourceTests.java @@ -21,10 +21,10 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.tests.sample.beans.SideEffectBean; +import org.springframework.beans.testfixture.beans.SideEffectBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Rod Johnson diff --git a/spring-aop/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java b/spring-aop/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java index bb5e6579d83c..7cb788ed1ac8 100644 --- a/spring-aop/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java @@ -21,11 +21,11 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.SideEffectBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.SideEffectBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Rod Johnson diff --git a/spring-aop/src/test/java/org/springframework/aop/target/dynamic/RefreshableTargetSourceTests.java b/spring-aop/src/test/java/org/springframework/aop/target/dynamic/RefreshableTargetSourceTests.java index dbfe7024c450..ac33fd950adb 100644 --- a/spring-aop/src/test/java/org/springframework/aop/target/dynamic/RefreshableTargetSourceTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/target/dynamic/RefreshableTargetSourceTests.java @@ -18,10 +18,10 @@ import org.junit.jupiter.api.Test; -import org.springframework.tests.EnabledForTestGroups; +import org.springframework.core.testfixture.EnabledForTestGroups; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestGroup.PERFORMANCE; +import static org.springframework.core.testfixture.TestGroup.PERFORMANCE; /** * @author Rob Harrop diff --git a/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerEventTests-context.xml b/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerEventTests-context.xml index 48da214eb4d6..64f222cdd372 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerEventTests-context.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerEventTests-context.xml @@ -20,7 +20,7 @@ - + diff --git a/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests-pointcutDuplication.xml b/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests-pointcutDuplication.xml index 1162d714f32e..33693b7c1c40 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests-pointcutDuplication.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests-pointcutDuplication.xml @@ -14,7 +14,7 @@ - + diff --git a/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests-pointcutMissing.xml b/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests-pointcutMissing.xml index b47670e08d34..3d2037805e41 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests-pointcutMissing.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/config/AopNamespaceHandlerPointcutErrorTests-pointcutMissing.xml @@ -14,7 +14,7 @@ - + diff --git a/spring-aop/src/test/resources/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests-context.xml b/spring-aop/src/test/resources/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests-context.xml index 1bfd0c2814b7..a5bf0f37d9c1 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests-context.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/interceptor/ExposeInvocationInterceptorTests-context.xml @@ -6,7 +6,7 @@ --> - + @@ -15,7 +15,7 @@ INSTANCE - + diff --git a/spring-aop/src/test/resources/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests-context.xml b/spring-aop/src/test/resources/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests-context.xml index e67171818b5d..967e42b6868a 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests-context.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/support/RegexpMethodPointcutAdvisorIntegrationTests-context.xml @@ -4,12 +4,12 @@ - + custom 666 - + @@ -21,15 +21,15 @@ - org.springframework.tests.sample.beans.ITestBean + org.springframework.beans.testfixture.beans.ITestBean settersAdvisor - org.springframework.tests.sample.beans.Person + org.springframework.beans.testfixture.beans.Person - + serializableSettersAdvised @@ -48,7 +48,7 @@ - org.springframework.tests.sample.beans.ITestBean + org.springframework.beans.testfixture.beans.ITestBean true diff --git a/spring-aop/src/test/resources/org/springframework/aop/target/CommonsPool2TargetSourceProxyTests-context.xml b/spring-aop/src/test/resources/org/springframework/aop/target/CommonsPool2TargetSourceProxyTests-context.xml index c3c614d4a634..c0bbd2fe9097 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/target/CommonsPool2TargetSourceProxyTests-context.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/target/CommonsPool2TargetSourceProxyTests-context.xml @@ -3,7 +3,7 @@ - + diff --git a/spring-aop/src/test/resources/org/springframework/aop/target/HotSwappableTargetSourceTests-context.xml b/spring-aop/src/test/resources/org/springframework/aop/target/HotSwappableTargetSourceTests-context.xml index dcc43922efd5..25f39f9f71da 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/target/HotSwappableTargetSourceTests-context.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/target/HotSwappableTargetSourceTests-context.xml @@ -4,11 +4,11 @@ - + 10 - + 20 diff --git a/spring-aop/src/test/resources/org/springframework/aop/target/LazyInitTargetSourceTests-customTarget.xml b/spring-aop/src/test/resources/org/springframework/aop/target/LazyInitTargetSourceTests-customTarget.xml index cec1c980ba5a..70f7406195da 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/target/LazyInitTargetSourceTests-customTarget.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/target/LazyInitTargetSourceTests-customTarget.xml @@ -3,7 +3,7 @@ - + 10 diff --git a/spring-aop/src/test/resources/org/springframework/aop/target/LazyInitTargetSourceTests-singleton.xml b/spring-aop/src/test/resources/org/springframework/aop/target/LazyInitTargetSourceTests-singleton.xml index 1e5c69f5499b..e10984760269 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/target/LazyInitTargetSourceTests-singleton.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/target/LazyInitTargetSourceTests-singleton.xml @@ -3,7 +3,7 @@ - + 10 diff --git a/spring-aop/src/test/resources/org/springframework/aop/target/PrototypeTargetSourceTests-context.xml b/spring-aop/src/test/resources/org/springframework/aop/target/PrototypeTargetSourceTests-context.xml index 4ee787b20fb4..53513ecf1df6 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/target/PrototypeTargetSourceTests-context.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/target/PrototypeTargetSourceTests-context.xml @@ -4,11 +4,11 @@ - + 10 - + 10 @@ -16,7 +16,7 @@ prototypeTest - + debugInterceptor,test diff --git a/spring-aop/src/test/resources/org/springframework/aop/target/ThreadLocalTargetSourceTests-context.xml b/spring-aop/src/test/resources/org/springframework/aop/target/ThreadLocalTargetSourceTests-context.xml index 6400db2f215f..778c8c1d7f0e 100644 --- a/spring-aop/src/test/resources/org/springframework/aop/target/ThreadLocalTargetSourceTests-context.xml +++ b/spring-aop/src/test/resources/org/springframework/aop/target/ThreadLocalTargetSourceTests-context.xml @@ -3,7 +3,7 @@ - + 10 @@ -11,7 +11,7 @@ prototypeTest - + - + Rod - + Kerry diff --git a/spring-aop/src/test/java/org/springframework/tests/aop/advice/CountingAfterReturningAdvice.java b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/CountingAfterReturningAdvice.java similarity index 90% rename from spring-aop/src/test/java/org/springframework/tests/aop/advice/CountingAfterReturningAdvice.java rename to spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/CountingAfterReturningAdvice.java index 2b10ce6408ee..8cfab3ca0127 100644 --- a/spring-aop/src/test/java/org/springframework/tests/aop/advice/CountingAfterReturningAdvice.java +++ b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/CountingAfterReturningAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.aop.advice; +package org.springframework.aop.testfixture.advice; import java.lang.reflect.Method; diff --git a/spring-aop/src/test/java/org/springframework/tests/aop/advice/CountingBeforeAdvice.java b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/CountingBeforeAdvice.java similarity index 90% rename from spring-aop/src/test/java/org/springframework/tests/aop/advice/CountingBeforeAdvice.java rename to spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/CountingBeforeAdvice.java index 8ccb4cc78387..bf931f6bdfaa 100644 --- a/spring-aop/src/test/java/org/springframework/tests/aop/advice/CountingBeforeAdvice.java +++ b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/CountingBeforeAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.aop.advice; +package org.springframework.aop.testfixture.advice; import java.lang.reflect.Method; diff --git a/spring-aop/src/test/java/org/springframework/tests/aop/advice/MethodCounter.java b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/MethodCounter.java similarity index 83% rename from spring-aop/src/test/java/org/springframework/tests/aop/advice/MethodCounter.java rename to spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/MethodCounter.java index 9527bdcd4d64..384973bd9aa7 100644 --- a/spring-aop/src/test/java/org/springframework/tests/aop/advice/MethodCounter.java +++ b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/MethodCounter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.aop.advice; +package org.springframework.aop.testfixture.advice; import java.io.Serializable; import java.lang.reflect.Method; @@ -25,6 +25,7 @@ * * @author Rod Johnson * @author Chris Beams + * @author Sam Brannen */ @SuppressWarnings("serial") public class MethodCounter implements Serializable { @@ -39,15 +40,12 @@ protected void count(Method m) { } protected void count(String methodName) { - Integer i = map.get(methodName); - i = (i != null) ? new Integer(i.intValue() + 1) : new Integer(1); - map.put(methodName, i); + map.merge(methodName, 1, (n, m) -> n + 1); ++allCount; } public int getCalls(String methodName) { - Integer i = map.get(methodName); - return (i != null ? i.intValue() : 0); + return map.getOrDefault(methodName, 0); } public int getCalls() { diff --git a/spring-aop/src/test/java/org/springframework/tests/aop/advice/MyThrowsHandler.java b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/MyThrowsHandler.java similarity index 95% rename from spring-aop/src/test/java/org/springframework/tests/aop/advice/MyThrowsHandler.java rename to spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/MyThrowsHandler.java index 5eec90e61634..606101af9c62 100644 --- a/spring-aop/src/test/java/org/springframework/tests/aop/advice/MyThrowsHandler.java +++ b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/MyThrowsHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.aop.advice; +package org.springframework.aop.testfixture.advice; import java.io.IOException; import java.lang.reflect.Method; @@ -24,10 +24,12 @@ @SuppressWarnings("serial") public class MyThrowsHandler extends MethodCounter implements ThrowsAdvice { + // Full method signature public void afterThrowing(Method m, Object[] args, Object target, IOException ex) { count("ioException"); } + public void afterThrowing(RemoteException ex) throws Throwable { count("remoteException"); } @@ -36,4 +38,5 @@ public void afterThrowing(RemoteException ex) throws Throwable { public void afterThrowing(Method m, Exception ex) throws Throwable { throw new UnsupportedOperationException("Shouldn't be called"); } + } diff --git a/spring-aop/src/test/java/org/springframework/tests/aop/advice/TimestampIntroductionAdvisor.java b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/TimestampIntroductionAdvisor.java similarity index 88% rename from spring-aop/src/test/java/org/springframework/tests/aop/advice/TimestampIntroductionAdvisor.java rename to spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/TimestampIntroductionAdvisor.java index 8e2d4b8cc23b..5321e5d38110 100644 --- a/spring-aop/src/test/java/org/springframework/tests/aop/advice/TimestampIntroductionAdvisor.java +++ b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/advice/TimestampIntroductionAdvisor.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.springframework.tests.aop.advice; +package org.springframework.aop.testfixture.advice; import org.springframework.aop.support.DefaultIntroductionAdvisor; import org.springframework.aop.support.DelegatingIntroductionInterceptor; -import org.springframework.tests.aop.interceptor.TimestampIntroductionInterceptor; +import org.springframework.aop.testfixture.interceptor.TimestampIntroductionInterceptor; /** * @author Rod Johnson diff --git a/spring-aop/src/test/java/org/springframework/tests/aop/interceptor/NopInterceptor.java b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/interceptor/NopInterceptor.java similarity index 96% rename from spring-aop/src/test/java/org/springframework/tests/aop/interceptor/NopInterceptor.java rename to spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/interceptor/NopInterceptor.java index 5c1855cbd4b6..dd4432467620 100644 --- a/spring-aop/src/test/java/org/springframework/tests/aop/interceptor/NopInterceptor.java +++ b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/interceptor/NopInterceptor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.aop.interceptor; +package org.springframework.aop.testfixture.interceptor; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; diff --git a/spring-aop/src/test/java/org/springframework/tests/aop/interceptor/SerializableNopInterceptor.java b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/interceptor/SerializableNopInterceptor.java similarity index 95% rename from spring-aop/src/test/java/org/springframework/tests/aop/interceptor/SerializableNopInterceptor.java rename to spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/interceptor/SerializableNopInterceptor.java index 7813c87f9f6d..25d9546c53a0 100644 --- a/spring-aop/src/test/java/org/springframework/tests/aop/interceptor/SerializableNopInterceptor.java +++ b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/interceptor/SerializableNopInterceptor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.aop.interceptor; +package org.springframework.aop.testfixture.interceptor; import java.io.Serializable; diff --git a/spring-aop/src/test/java/org/springframework/tests/aop/interceptor/TimestampIntroductionInterceptor.java b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/interceptor/TimestampIntroductionInterceptor.java similarity index 90% rename from spring-aop/src/test/java/org/springframework/tests/aop/interceptor/TimestampIntroductionInterceptor.java rename to spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/interceptor/TimestampIntroductionInterceptor.java index 8e665dba6567..24761350132a 100644 --- a/spring-aop/src/test/java/org/springframework/tests/aop/interceptor/TimestampIntroductionInterceptor.java +++ b/spring-aop/src/testFixtures/java/org/springframework/aop/testfixture/interceptor/TimestampIntroductionInterceptor.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.springframework.tests.aop.interceptor; +package org.springframework.aop.testfixture.interceptor; import org.springframework.aop.support.DelegatingIntroductionInterceptor; -import org.springframework.tests.TimeStamped; +import org.springframework.core.testfixture.TimeStamped; @SuppressWarnings("serial") public class TimestampIntroductionInterceptor extends DelegatingIntroductionInterceptor diff --git a/spring-aspects/spring-aspects.gradle b/spring-aspects/spring-aspects.gradle index b30a8107f987..12adbfb7e5f4 100644 --- a/spring-aspects/spring-aspects.gradle +++ b/spring-aspects/spring-aspects.gradle @@ -11,7 +11,6 @@ sourceSets.test.java.srcDirs = files() aspectj.version = dependencyManagement.managedVersions['org.aspectj:aspectjweaver'] dependencies { - aspect(project(":spring-orm")) compile("org.aspectj:aspectjweaver") compileOnly("org.aspectj:aspectjrt") optional(project(":spring-aop")) // for @Async support @@ -24,6 +23,10 @@ dependencies { optional("javax.transaction:javax.transaction-api") // for @javax.transaction.Transactional support testCompile(project(":spring-core")) // for CodeStyleAspect testCompile(project(":spring-test")) + testCompile(testFixtures(project(":spring-context"))) + testCompile(testFixtures(project(":spring-context-support"))) + testCompile(testFixtures(project(":spring-core"))) + testCompile(testFixtures(project(":spring-tx"))) testCompile("javax.mail:javax.mail-api") testCompileOnly("org.aspectj:aspectjrt") } diff --git a/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AbstractInterfaceDrivenDependencyInjectionAspect.aj b/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AbstractInterfaceDrivenDependencyInjectionAspect.aj index f48e0d9252e5..6e049a58a045 100644 --- a/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AbstractInterfaceDrivenDependencyInjectionAspect.aj +++ b/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AbstractInterfaceDrivenDependencyInjectionAspect.aj @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -67,6 +67,7 @@ import java.io.Serializable; * @since 2.5.2 */ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends AbstractDependencyInjectionAspect { + /** * Select initialization join point as object construction */ diff --git a/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AnnotationBeanConfigurerAspect.aj b/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AnnotationBeanConfigurerAspect.aj index 98599fb2e4e2..923e459b4438 100644 --- a/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AnnotationBeanConfigurerAspect.aj +++ b/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AnnotationBeanConfigurerAspect.aj @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,22 +47,26 @@ import org.springframework.beans.factory.wiring.BeanConfigurerSupport; public aspect AnnotationBeanConfigurerAspect extends AbstractInterfaceDrivenDependencyInjectionAspect implements BeanFactoryAware, InitializingBean, DisposableBean { - private BeanConfigurerSupport beanConfigurerSupport = new BeanConfigurerSupport(); + private final BeanConfigurerSupport beanConfigurerSupport = new BeanConfigurerSupport(); + @Override public void setBeanFactory(BeanFactory beanFactory) { this.beanConfigurerSupport.setBeanWiringInfoResolver(new AnnotationBeanWiringInfoResolver()); this.beanConfigurerSupport.setBeanFactory(beanFactory); } + @Override public void afterPropertiesSet() { this.beanConfigurerSupport.afterPropertiesSet(); } + @Override public void configureBean(Object bean) { this.beanConfigurerSupport.configureBean(bean); } + @Override public void destroy() { this.beanConfigurerSupport.destroy(); } diff --git a/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AspectJAsyncConfiguration.java b/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AspectJAsyncConfiguration.java index ef93148652ac..e13a595b42d4 100644 --- a/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AspectJAsyncConfiguration.java +++ b/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AspectJAsyncConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ * @see org.springframework.scheduling.annotation.ProxyAsyncConfiguration */ @Configuration +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class AspectJAsyncConfiguration extends AbstractAsyncConfiguration { @Bean(name = TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME) diff --git a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj index aed8e4ab65a8..782ca35e0777 100644 --- a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj +++ b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,7 +59,8 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor @Override public void destroy() { - clearTransactionManagerCache(); // An aspect is basically a singleton + // An aspect is basically a singleton -> cleanup on destruction + clearTransactionManagerCache(); } @SuppressAjWarnings("adviceDidNotMatch") diff --git a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AspectJJtaTransactionManagementConfiguration.java b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AspectJJtaTransactionManagementConfiguration.java index caa7cc3c2f72..ec733d3cf2b9 100644 --- a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AspectJJtaTransactionManagementConfiguration.java +++ b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AspectJJtaTransactionManagementConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ * @see TransactionManagementConfigurationSelector */ @Configuration +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class AspectJJtaTransactionManagementConfiguration extends AspectJTransactionManagementConfiguration { @Bean(name = TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_BEAN_NAME) diff --git a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AspectJTransactionManagementConfiguration.java b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AspectJTransactionManagementConfiguration.java index 2784a733e7c2..2c99c3050744 100644 --- a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AspectJTransactionManagementConfiguration.java +++ b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AspectJTransactionManagementConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,7 @@ * @see AspectJJtaTransactionManagementConfiguration */ @Configuration +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class AspectJTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME) diff --git a/spring-aspects/src/test/java/org/springframework/cache/aspectj/AbstractCacheAnnotationTests.java b/spring-aspects/src/test/java/org/springframework/cache/aspectj/AbstractCacheAnnotationTests.java new file mode 100644 index 000000000000..eed37f21ec04 --- /dev/null +++ b/spring-aspects/src/test/java/org/springframework/cache/aspectj/AbstractCacheAnnotationTests.java @@ -0,0 +1,882 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.cache.aspectj; + +import java.util.Collection; +import java.util.UUID; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.aop.framework.AopProxyUtils; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.config.AnnotatedClassCacheableService; +import org.springframework.cache.config.CacheableService; +import org.springframework.cache.config.TestEntity; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.testfixture.cache.SomeCustomKeyGenerator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIOException; + +/** + * Copy of the shared {@code AbstractCacheAnnotationTests}: necessary + * due to issues with Gradle test fixtures and AspectJ configuration + * in the Gradle build. + * + *

Abstract cache annotation tests (containing several reusable methods). + * + * @author Costin Leau + * @author Chris Beams + * @author Phillip Webb + * @author Stephane Nicoll + */ +public abstract class AbstractCacheAnnotationTests { + + protected ConfigurableApplicationContext ctx; + + protected CacheableService cs; + + protected CacheableService ccs; + + protected CacheManager cm; + + + /** + * @return a refreshed application context + */ + protected abstract ConfigurableApplicationContext getApplicationContext(); + + + @BeforeEach + public void setup() { + this.ctx = getApplicationContext(); + this.cs = ctx.getBean("service", CacheableService.class); + this.ccs = ctx.getBean("classService", CacheableService.class); + this.cm = ctx.getBean("cacheManager", CacheManager.class); + + Collection cn = this.cm.getCacheNames(); + assertThat(cn).containsOnly("testCache", "secondary", "primary"); + } + + @AfterEach + public void close() { + if (this.ctx != null) { + this.ctx.close(); + } + } + + + protected void testCacheable(CacheableService service) { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + Object r3 = service.cache(o1); + + assertThat(r2).isSameAs(r1); + assertThat(r3).isSameAs(r1); + } + + protected void testCacheableNull(CacheableService service) { + Object o1 = new Object(); + assertThat(this.cm.getCache("testCache").get(o1)).isNull(); + + Object r1 = service.cacheNull(o1); + Object r2 = service.cacheNull(o1); + Object r3 = service.cacheNull(o1); + + assertThat(r2).isSameAs(r1); + assertThat(r3).isSameAs(r1); + + assertThat(this.cm.getCache("testCache")).as("testCache").isNotNull(); + assertThat(this.cm.getCache("testCache").get(o1)).as("cached object").isNotNull(); + assertThat(this.cm.getCache("testCache").get(o1).get()).isEqualTo(r3); + assertThat(r3).as("Cached value should be null").isNull(); + } + + protected void testCacheableSync(CacheableService service) { + Object o1 = new Object(); + + Object r1 = service.cacheSync(o1); + Object r2 = service.cacheSync(o1); + Object r3 = service.cacheSync(o1); + + assertThat(r2).isSameAs(r1); + assertThat(r3).isSameAs(r1); + } + + protected void testCacheableSyncNull(CacheableService service) { + Object o1 = new Object(); + assertThat(this.cm.getCache("testCache").get(o1)).isNull(); + + Object r1 = service.cacheSyncNull(o1); + Object r2 = service.cacheSyncNull(o1); + Object r3 = service.cacheSyncNull(o1); + + assertThat(r2).isSameAs(r1); + assertThat(r3).isSameAs(r1); + + assertThat(this.cm.getCache("testCache").get(o1).get()).isEqualTo(r3); + assertThat(r3).as("Cached value should be null").isNull(); + } + + protected void testEvict(CacheableService service, boolean successExpected) { + Cache cache = this.cm.getCache("testCache"); + + Object o1 = new Object(); + cache.putIfAbsent(o1, -1L); + Object r1 = service.cache(o1); + + service.evict(o1, null); + if (successExpected) { + assertThat(cache.get(o1)).isNull(); + } + else { + assertThat(cache.get(o1)).isNotNull(); + } + + Object r2 = service.cache(o1); + if (successExpected) { + assertThat(r2).isNotSameAs(r1); + } + else { + assertThat(r2).isSameAs(r1); + } + } + + protected void testEvictEarly(CacheableService service) { + Cache cache = this.cm.getCache("testCache"); + + Object o1 = new Object(); + cache.putIfAbsent(o1, -1L); + Object r1 = service.cache(o1); + + try { + service.evictEarly(o1); + } + catch (RuntimeException ex) { + // expected + } + assertThat(cache.get(o1)).isNull(); + + Object r2 = service.cache(o1); + assertThat(r2).isNotSameAs(r1); + } + + protected void testEvictException(CacheableService service) { + Object o1 = new Object(); + Object r1 = service.cache(o1); + + try { + service.evictWithException(o1); + } + catch (RuntimeException ex) { + // expected + } + // exception occurred, eviction skipped, data should still be in the cache + Object r2 = service.cache(o1); + assertThat(r2).isSameAs(r1); + } + + protected void testEvictWithKey(CacheableService service) { + Object o1 = new Object(); + Object r1 = service.cache(o1); + + service.evict(o1, null); + Object r2 = service.cache(o1); + assertThat(r2).isNotSameAs(r1); + } + + protected void testEvictWithKeyEarly(CacheableService service) { + Object o1 = new Object(); + Object r1 = service.cache(o1); + + try { + service.evictEarly(o1); + } + catch (Exception ex) { + // expected + } + Object r2 = service.cache(o1); + assertThat(r2).isNotSameAs(r1); + } + + protected void testEvictAll(CacheableService service, boolean successExpected) { + Cache cache = this.cm.getCache("testCache"); + + Object o1 = new Object(); + Object o2 = new Object(); + cache.putIfAbsent(o1, -1L); + cache.putIfAbsent(o2, -2L); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o2); + assertThat(r2).isNotSameAs(r1); + + service.evictAll(new Object()); + if (successExpected) { + assertThat(cache.get(o1)).isNull(); + assertThat(cache.get(o2)).isNull(); + } + else { + assertThat(cache.get(o1)).isNotNull(); + assertThat(cache.get(o2)).isNotNull(); + } + + Object r3 = service.cache(o1); + Object r4 = service.cache(o2); + if (successExpected) { + assertThat(r3).isNotSameAs(r1); + assertThat(r4).isNotSameAs(r2); + } + else { + assertThat(r3).isSameAs(r1); + assertThat(r4).isSameAs(r2); + } + } + + protected void testEvictAllEarly(CacheableService service) { + Cache cache = this.cm.getCache("testCache"); + + Object o1 = new Object(); + Object o2 = new Object(); + cache.putIfAbsent(o1, -1L); + cache.putIfAbsent(o2, -2L); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o2); + assertThat(r2).isNotSameAs(r1); + + try { + service.evictAllEarly(new Object()); + } + catch (Exception ex) { + // expected + } + assertThat(cache.get(o1)).isNull(); + assertThat(cache.get(o2)).isNull(); + + Object r3 = service.cache(o1); + Object r4 = service.cache(o2); + assertThat(r3).isNotSameAs(r1); + assertThat(r4).isNotSameAs(r2); + } + + protected void testConditionalExpression(CacheableService service) { + Object r1 = service.conditional(4); + Object r2 = service.conditional(4); + + assertThat(r2).isNotSameAs(r1); + + Object r3 = service.conditional(3); + Object r4 = service.conditional(3); + + assertThat(r4).isSameAs(r3); + } + + protected void testConditionalExpressionSync(CacheableService service) { + Object r1 = service.conditionalSync(4); + Object r2 = service.conditionalSync(4); + + assertThat(r2).isNotSameAs(r1); + + Object r3 = service.conditionalSync(3); + Object r4 = service.conditionalSync(3); + + assertThat(r4).isSameAs(r3); + } + + protected void testUnlessExpression(CacheableService service) { + Cache cache = this.cm.getCache("testCache"); + cache.clear(); + service.unless(10); + service.unless(11); + assertThat(cache.get(10).get()).isEqualTo(10L); + assertThat(cache.get(11)).isNull(); + } + + protected void testKeyExpression(CacheableService service) { + Object r1 = service.key(5, 1); + Object r2 = service.key(5, 2); + + assertThat(r2).isSameAs(r1); + + Object r3 = service.key(1, 5); + Object r4 = service.key(2, 5); + + assertThat(r4).isNotSameAs(r3); + } + + protected void testVarArgsKey(CacheableService service) { + Object r1 = service.varArgsKey(1, 2, 3); + Object r2 = service.varArgsKey(1, 2, 3); + + assertThat(r2).isSameAs(r1); + + Object r3 = service.varArgsKey(1, 2, 3); + Object r4 = service.varArgsKey(1, 2); + + assertThat(r4).isNotSameAs(r3); + } + + protected void testNullValue(CacheableService service) { + Object key = new Object(); + assertThat(service.nullValue(key)).isNull(); + int nr = service.nullInvocations().intValue(); + assertThat(service.nullValue(key)).isNull(); + assertThat(service.nullInvocations().intValue()).isEqualTo(nr); + assertThat(service.nullValue(new Object())).isNull(); + assertThat(service.nullInvocations().intValue()).isEqualTo(nr + 1); + } + + protected void testMethodName(CacheableService service, String keyName) { + Object key = new Object(); + Object r1 = service.name(key); + assertThat(service.name(key)).isSameAs(r1); + Cache cache = this.cm.getCache("testCache"); + // assert the method name is used + assertThat(cache.get(keyName)).isNotNull(); + } + + protected void testRootVars(CacheableService service) { + Object key = new Object(); + Object r1 = service.rootVars(key); + assertThat(service.rootVars(key)).isSameAs(r1); + Cache cache = this.cm.getCache("testCache"); + // assert the method name is used + String expectedKey = "rootVarsrootVars" + AopProxyUtils.ultimateTargetClass(service) + service; + assertThat(cache.get(expectedKey)).isNotNull(); + } + + protected void testCheckedThrowable(CacheableService service) { + String arg = UUID.randomUUID().toString(); + assertThatIOException().isThrownBy(() -> + service.throwChecked(arg)) + .withMessage(arg); + } + + protected void testUncheckedThrowable(CacheableService service) { + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> + service.throwUnchecked(1L)) + .withMessage("1"); + } + + protected void testCheckedThrowableSync(CacheableService service) { + String arg = UUID.randomUUID().toString(); + assertThatIOException().isThrownBy(() -> + service.throwCheckedSync(arg)) + .withMessage(arg); + } + + protected void testUncheckedThrowableSync(CacheableService service) { + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> + service.throwUncheckedSync(1L)) + .withMessage("1"); + } + + protected void testNullArg(CacheableService service) { + Object r1 = service.cache(null); + assertThat(service.cache(null)).isSameAs(r1); + } + + protected void testCacheUpdate(CacheableService service) { + Object o = new Object(); + Cache cache = this.cm.getCache("testCache"); + assertThat(cache.get(o)).isNull(); + Object r1 = service.update(o); + assertThat(cache.get(o).get()).isSameAs(r1); + + o = new Object(); + assertThat(cache.get(o)).isNull(); + Object r2 = service.update(o); + assertThat(cache.get(o).get()).isSameAs(r2); + } + + protected void testConditionalCacheUpdate(CacheableService service) { + Integer one = 1; + Integer three = 3; + + Cache cache = this.cm.getCache("testCache"); + assertThat((int) Integer.valueOf(service.conditionalUpdate(one).toString())).isEqualTo((int) one); + assertThat(cache.get(one)).isNull(); + + assertThat((int) Integer.valueOf(service.conditionalUpdate(three).toString())).isEqualTo((int) three); + assertThat((int) Integer.valueOf(cache.get(three).get().toString())).isEqualTo((int) three); + } + + protected void testMultiCache(CacheableService service) { + Object o1 = new Object(); + Object o2 = new Object(); + + Cache primary = this.cm.getCache("primary"); + Cache secondary = this.cm.getCache("secondary"); + + assertThat(primary.get(o1)).isNull(); + assertThat(secondary.get(o1)).isNull(); + Object r1 = service.multiCache(o1); + assertThat(primary.get(o1).get()).isSameAs(r1); + assertThat(secondary.get(o1).get()).isSameAs(r1); + + Object r2 = service.multiCache(o1); + Object r3 = service.multiCache(o1); + + assertThat(r2).isSameAs(r1); + assertThat(r3).isSameAs(r1); + + assertThat(primary.get(o2)).isNull(); + assertThat(secondary.get(o2)).isNull(); + Object r4 = service.multiCache(o2); + assertThat(primary.get(o2).get()).isSameAs(r4); + assertThat(secondary.get(o2).get()).isSameAs(r4); + } + + protected void testMultiEvict(CacheableService service) { + Object o1 = new Object(); + Object o2 = o1.toString() + "A"; + + + Object r1 = service.multiCache(o1); + Object r2 = service.multiCache(o1); + + Cache primary = this.cm.getCache("primary"); + Cache secondary = this.cm.getCache("secondary"); + + primary.put(o2, o2); + assertThat(r2).isSameAs(r1); + assertThat(primary.get(o1).get()).isSameAs(r1); + assertThat(secondary.get(o1).get()).isSameAs(r1); + + service.multiEvict(o1); + assertThat(primary.get(o1)).isNull(); + assertThat(secondary.get(o1)).isNull(); + assertThat(primary.get(o2)).isNull(); + + Object r3 = service.multiCache(o1); + Object r4 = service.multiCache(o1); + assertThat(r3).isNotSameAs(r1); + assertThat(r4).isSameAs(r3); + + assertThat(primary.get(o1).get()).isSameAs(r3); + assertThat(secondary.get(o1).get()).isSameAs(r4); + } + + protected void testMultiPut(CacheableService service) { + Object o = 1; + + Cache primary = this.cm.getCache("primary"); + Cache secondary = this.cm.getCache("secondary"); + + assertThat(primary.get(o)).isNull(); + assertThat(secondary.get(o)).isNull(); + Object r1 = service.multiUpdate(o); + assertThat(primary.get(o).get()).isSameAs(r1); + assertThat(secondary.get(o).get()).isSameAs(r1); + + o = 2; + assertThat(primary.get(o)).isNull(); + assertThat(secondary.get(o)).isNull(); + Object r2 = service.multiUpdate(o); + assertThat(primary.get(o).get()).isSameAs(r2); + assertThat(secondary.get(o).get()).isSameAs(r2); + } + + protected void testPutRefersToResult(CacheableService service) { + Long id = Long.MIN_VALUE; + TestEntity entity = new TestEntity(); + Cache primary = this.cm.getCache("primary"); + assertThat(primary.get(id)).isNull(); + assertThat(entity.getId()).isNull(); + service.putRefersToResult(entity); + assertThat(primary.get(id).get()).isSameAs(entity); + } + + protected void testMultiCacheAndEvict(CacheableService service) { + String methodName = "multiCacheAndEvict"; + + Cache primary = this.cm.getCache("primary"); + Cache secondary = this.cm.getCache("secondary"); + Object key = 1; + + secondary.put(key, key); + + assertThat(secondary.get(methodName)).isNull(); + assertThat(secondary.get(key).get()).isSameAs(key); + + Object r1 = service.multiCacheAndEvict(key); + assertThat(service.multiCacheAndEvict(key)).isSameAs(r1); + + // assert the method name is used + assertThat(primary.get(methodName).get()).isSameAs(r1); + assertThat(secondary.get(methodName)).isNull(); + assertThat(secondary.get(key)).isNull(); + } + + protected void testMultiConditionalCacheAndEvict(CacheableService service) { + Cache primary = this.cm.getCache("primary"); + Cache secondary = this.cm.getCache("secondary"); + Object key = 1; + + secondary.put(key, key); + + assertThat(primary.get(key)).isNull(); + assertThat(secondary.get(key).get()).isSameAs(key); + + Object r1 = service.multiConditionalCacheAndEvict(key); + Object r3 = service.multiConditionalCacheAndEvict(key); + + assertThat(!r1.equals(r3)).isTrue(); + assertThat(primary.get(key)).isNull(); + + Object key2 = 3; + Object r2 = service.multiConditionalCacheAndEvict(key2); + assertThat(service.multiConditionalCacheAndEvict(key2)).isSameAs(r2); + + // assert the method name is used + assertThat(primary.get(key2).get()).isSameAs(r2); + assertThat(secondary.get(key2)).isNull(); + } + + @Test + public void testCacheable() { + testCacheable(this.cs); + } + + @Test + public void testCacheableNull() { + testCacheableNull(this.cs); + } + + @Test + public void testCacheableSync() { + testCacheableSync(this.cs); + } + + @Test + public void testCacheableSyncNull() { + testCacheableSyncNull(this.cs); + } + + @Test + public void testEvict() { + testEvict(this.cs, true); + } + + @Test + public void testEvictEarly() { + testEvictEarly(this.cs); + } + + @Test + public void testEvictWithException() { + testEvictException(this.cs); + } + + @Test + public void testEvictAll() { + testEvictAll(this.cs, true); + } + + @Test + public void testEvictAllEarly() { + testEvictAllEarly(this.cs); + } + + @Test + public void testEvictWithKey() { + testEvictWithKey(this.cs); + } + + @Test + public void testEvictWithKeyEarly() { + testEvictWithKeyEarly(this.cs); + } + + @Test + public void testConditionalExpression() { + testConditionalExpression(this.cs); + } + + @Test + public void testConditionalExpressionSync() { + testConditionalExpressionSync(this.cs); + } + + @Test + public void testUnlessExpression() { + testUnlessExpression(this.cs); + } + + @Test + public void testClassCacheUnlessExpression() { + testUnlessExpression(this.cs); + } + + @Test + public void testKeyExpression() { + testKeyExpression(this.cs); + } + + @Test + public void testVarArgsKey() { + testVarArgsKey(this.cs); + } + + @Test + public void testClassCacheCacheable() { + testCacheable(this.ccs); + } + + @Test + public void testClassCacheEvict() { + testEvict(this.ccs, true); + } + + @Test + public void testClassEvictEarly() { + testEvictEarly(this.ccs); + } + + @Test + public void testClassEvictAll() { + testEvictAll(this.ccs, true); + } + + @Test + public void testClassEvictWithException() { + testEvictException(this.ccs); + } + + @Test + public void testClassCacheEvictWithWKey() { + testEvictWithKey(this.ccs); + } + + @Test + public void testClassEvictWithKeyEarly() { + testEvictWithKeyEarly(this.ccs); + } + + @Test + public void testNullValue() { + testNullValue(this.cs); + } + + @Test + public void testClassNullValue() { + Object key = new Object(); + assertThat(this.ccs.nullValue(key)).isNull(); + int nr = this.ccs.nullInvocations().intValue(); + assertThat(this.ccs.nullValue(key)).isNull(); + assertThat(this.ccs.nullInvocations().intValue()).isEqualTo(nr); + assertThat(this.ccs.nullValue(new Object())).isNull(); + // the check method is also cached + assertThat(this.ccs.nullInvocations().intValue()).isEqualTo(nr); + assertThat(AnnotatedClassCacheableService.nullInvocations.intValue()).isEqualTo(nr + 1); + } + + @Test + public void testMethodName() { + testMethodName(this.cs, "name"); + } + + @Test + public void testClassMethodName() { + testMethodName(this.ccs, "nametestCache"); + } + + @Test + public void testRootVars() { + testRootVars(this.cs); + } + + @Test + public void testClassRootVars() { + testRootVars(this.ccs); + } + + @Test + public void testCustomKeyGenerator() { + Object param = new Object(); + Object r1 = this.cs.customKeyGenerator(param); + assertThat(this.cs.customKeyGenerator(param)).isSameAs(r1); + Cache cache = this.cm.getCache("testCache"); + // Checks that the custom keyGenerator was used + Object expectedKey = SomeCustomKeyGenerator.generateKey("customKeyGenerator", param); + assertThat(cache.get(expectedKey)).isNotNull(); + } + + @Test + public void testUnknownCustomKeyGenerator() { + Object param = new Object(); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> + this.cs.unknownCustomKeyGenerator(param)); + } + + @Test + public void testCustomCacheManager() { + CacheManager customCm = this.ctx.getBean("customCacheManager", CacheManager.class); + Object key = new Object(); + Object r1 = this.cs.customCacheManager(key); + assertThat(this.cs.customCacheManager(key)).isSameAs(r1); + + Cache cache = customCm.getCache("testCache"); + assertThat(cache.get(key)).isNotNull(); + } + + @Test + public void testUnknownCustomCacheManager() { + Object param = new Object(); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> + this.cs.unknownCustomCacheManager(param)); + } + + @Test + public void testNullArg() { + testNullArg(this.cs); + } + + @Test + public void testClassNullArg() { + testNullArg(this.ccs); + } + + @Test + public void testCheckedException() { + testCheckedThrowable(this.cs); + } + + @Test + public void testClassCheckedException() { + testCheckedThrowable(this.ccs); + } + + @Test + public void testCheckedExceptionSync() { + testCheckedThrowableSync(this.cs); + } + + @Test + public void testClassCheckedExceptionSync() { + testCheckedThrowableSync(this.ccs); + } + + @Test + public void testUncheckedException() { + testUncheckedThrowable(this.cs); + } + + @Test + public void testClassUncheckedException() { + testUncheckedThrowable(this.ccs); + } + + @Test + public void testUncheckedExceptionSync() { + testUncheckedThrowableSync(this.cs); + } + + @Test + public void testClassUncheckedExceptionSync() { + testUncheckedThrowableSync(this.ccs); + } + + @Test + public void testUpdate() { + testCacheUpdate(this.cs); + } + + @Test + public void testClassUpdate() { + testCacheUpdate(this.ccs); + } + + @Test + public void testConditionalUpdate() { + testConditionalCacheUpdate(this.cs); + } + + @Test + public void testClassConditionalUpdate() { + testConditionalCacheUpdate(this.ccs); + } + + @Test + public void testMultiCache() { + testMultiCache(this.cs); + } + + @Test + public void testClassMultiCache() { + testMultiCache(this.ccs); + } + + @Test + public void testMultiEvict() { + testMultiEvict(this.cs); + } + + @Test + public void testClassMultiEvict() { + testMultiEvict(this.ccs); + } + + @Test + public void testMultiPut() { + testMultiPut(this.cs); + } + + @Test + public void testClassMultiPut() { + testMultiPut(this.ccs); + } + + @Test + public void testPutRefersToResult() { + testPutRefersToResult(this.cs); + } + + @Test + public void testClassPutRefersToResult() { + testPutRefersToResult(this.ccs); + } + + @Test + public void testMultiCacheAndEvict() { + testMultiCacheAndEvict(this.cs); + } + + @Test + public void testClassMultiCacheAndEvict() { + testMultiCacheAndEvict(this.ccs); + } + + @Test + public void testMultiConditionalCacheAndEvict() { + testMultiConditionalCacheAndEvict(this.cs); + } + + @Test + public void testClassMultiConditionalCacheAndEvict() { + testMultiConditionalCacheAndEvict(this.ccs); + } + +} diff --git a/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJCacheAnnotationTests.java b/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJCacheAnnotationTests.java index e952eacd3b00..4601c0ea814c 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJCacheAnnotationTests.java +++ b/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJCacheAnnotationTests.java @@ -19,7 +19,6 @@ import org.junit.jupiter.api.Test; import org.springframework.cache.Cache; -import org.springframework.cache.config.AbstractCacheAnnotationTests; import org.springframework.cache.config.CacheableService; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; diff --git a/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJEnableCachingIsolatedTests.java b/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJEnableCachingIsolatedTests.java index 57b9b90f5596..7ca1037efbc4 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJEnableCachingIsolatedTests.java +++ b/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJEnableCachingIsolatedTests.java @@ -22,14 +22,8 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.cache.CacheManager; -import org.springframework.cache.CacheTestUtils; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.config.AnnotatedClassCacheableService; -import org.springframework.cache.config.CacheableService; -import org.springframework.cache.config.DefaultCacheableService; -import org.springframework.cache.config.SomeCustomKeyGenerator; -import org.springframework.cache.config.SomeKeyGenerator; import org.springframework.cache.interceptor.CacheErrorHandler; import org.springframework.cache.interceptor.CacheResolver; import org.springframework.cache.interceptor.KeyGenerator; @@ -42,6 +36,12 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.testfixture.cache.CacheTestUtils; +import org.springframework.context.testfixture.cache.SomeCustomKeyGenerator; +import org.springframework.context.testfixture.cache.SomeKeyGenerator; +import org.springframework.context.testfixture.cache.beans.AnnotatedClassCacheableService; +import org.springframework.context.testfixture.cache.beans.CacheableService; +import org.springframework.context.testfixture.cache.beans.DefaultCacheableService; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJEnableCachingTests.java b/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJEnableCachingTests.java index 7857394de16f..7e693d6ea13a 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJEnableCachingTests.java +++ b/spring-aspects/src/test/java/org/springframework/cache/aspectj/AspectJEnableCachingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,15 +17,11 @@ package org.springframework.cache.aspectj; import org.springframework.cache.CacheManager; -import org.springframework.cache.CacheTestUtils; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.config.AbstractCacheAnnotationTests; import org.springframework.cache.config.AnnotatedClassCacheableService; import org.springframework.cache.config.CacheableService; import org.springframework.cache.config.DefaultCacheableService; -import org.springframework.cache.config.SomeCustomKeyGenerator; -import org.springframework.cache.config.SomeKeyGenerator; import org.springframework.cache.interceptor.CacheErrorHandler; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.cache.interceptor.SimpleCacheErrorHandler; @@ -34,6 +30,9 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.testfixture.cache.CacheTestUtils; +import org.springframework.context.testfixture.cache.SomeCustomKeyGenerator; +import org.springframework.context.testfixture.cache.SomeKeyGenerator; /** * @author Stephane Nicoll diff --git a/spring-aspects/src/test/java/org/springframework/cache/aspectj/JCacheAspectJJavaConfigTests.java b/spring-aspects/src/test/java/org/springframework/cache/aspectj/JCacheAspectJJavaConfigTests.java index c48ad735e6a9..dc278365d727 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/aspectj/JCacheAspectJJavaConfigTests.java +++ b/spring-aspects/src/test/java/org/springframework/cache/aspectj/JCacheAspectJJavaConfigTests.java @@ -23,13 +23,13 @@ import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.concurrent.ConcurrentMapCache; import org.springframework.cache.config.AnnotatedJCacheableService; -import org.springframework.cache.jcache.config.AbstractJCacheAnnotationTests; import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.contextsupport.testfixture.jcache.AbstractJCacheAnnotationTests; /** * @author Stephane Nicoll diff --git a/spring-aspects/src/test/java/org/springframework/cache/aspectj/JCacheAspectJNamespaceConfigTests.java b/spring-aspects/src/test/java/org/springframework/cache/aspectj/JCacheAspectJNamespaceConfigTests.java index a3e924e35502..c755d8c3f4aa 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/aspectj/JCacheAspectJNamespaceConfigTests.java +++ b/spring-aspects/src/test/java/org/springframework/cache/aspectj/JCacheAspectJNamespaceConfigTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,24 @@ package org.springframework.cache.aspectj; -import org.springframework.cache.jcache.config.AbstractJCacheAnnotationTests; import org.springframework.context.ApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; +import org.springframework.contextsupport.testfixture.jcache.AbstractJCacheAnnotationTests; /** * @author Stephane Nicoll + * @author Sam Brannen */ public class JCacheAspectJNamespaceConfigTests extends AbstractJCacheAnnotationTests { @Override protected ApplicationContext getApplicationContext() { - return new GenericXmlApplicationContext( - "/org/springframework/cache/config/annotation-jcache-aspectj.xml"); + GenericXmlApplicationContext context = new GenericXmlApplicationContext(); + // Disallow bean definition overriding to test https://github.com/spring-projects/spring-framework/pull/27499 + context.setAllowBeanDefinitionOverriding(false); + context.load("/org/springframework/cache/config/annotation-jcache-aspectj.xml"); + context.refresh(); + return context; } } diff --git a/spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java b/spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java index 5872dffc7808..fa494c921280 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java +++ b/spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java @@ -25,6 +25,10 @@ import org.springframework.cache.annotation.Caching; /** + * Copy of the shared {@code AbstractCacheAnnotationTests}: necessary + * due to issues with Gradle test fixtures and AspectJ configuration + * in the Gradle build. + * * @author Costin Leau * @author Phillip Webb * @author Stephane Nicoll diff --git a/spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedJCacheableService.java b/spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedJCacheableService.java index 299f76bf8f61..0b004f46b910 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedJCacheableService.java +++ b/spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedJCacheableService.java @@ -30,9 +30,9 @@ import org.springframework.cache.Cache; import org.springframework.cache.interceptor.SimpleKeyGenerator; -import org.springframework.cache.jcache.config.JCacheableService; -import org.springframework.cache.jcache.support.TestableCacheKeyGenerator; -import org.springframework.cache.jcache.support.TestableCacheResolverFactory; +import org.springframework.contextsupport.testfixture.cache.TestableCacheKeyGenerator; +import org.springframework.contextsupport.testfixture.cache.TestableCacheResolverFactory; +import org.springframework.contextsupport.testfixture.jcache.JCacheableService; /** * Repository sample with a @CacheDefaults annotation diff --git a/spring-aspects/src/test/java/org/springframework/cache/config/CacheableService.java b/spring-aspects/src/test/java/org/springframework/cache/config/CacheableService.java index e5ab4a5f94cc..3ec6212bac60 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/config/CacheableService.java +++ b/spring-aspects/src/test/java/org/springframework/cache/config/CacheableService.java @@ -17,7 +17,11 @@ package org.springframework.cache.config; /** - * Basic service interface for caching tests. + * Copy of the shared {@code CacheableService}: necessary + * due to issues with Gradle test fixtures and AspectJ configuration + * in the Gradle build. + * + *

Basic service interface for caching tests. * * @author Costin Leau * @author Phillip Webb diff --git a/spring-aspects/src/test/java/org/springframework/cache/config/DefaultCacheableService.java b/spring-aspects/src/test/java/org/springframework/cache/config/DefaultCacheableService.java index 7df2bb4ea27d..47a3a83a34a1 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/config/DefaultCacheableService.java +++ b/spring-aspects/src/test/java/org/springframework/cache/config/DefaultCacheableService.java @@ -25,7 +25,11 @@ import org.springframework.cache.annotation.Caching; /** - * Simple cacheable service. + * Copy of the shared {@code DefaultCacheableService}: necessary + * due to issues with Gradle test fixtures and AspectJ configuration + * in the Gradle build. + * + *

Simple cacheable service. * * @author Costin Leau * @author Phillip Webb diff --git a/spring-aspects/src/test/java/org/springframework/cache/config/TestEntity.java b/spring-aspects/src/test/java/org/springframework/cache/config/TestEntity.java index 087019a37641..b308741ee147 100644 --- a/spring-aspects/src/test/java/org/springframework/cache/config/TestEntity.java +++ b/spring-aspects/src/test/java/org/springframework/cache/config/TestEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,11 @@ import org.springframework.util.ObjectUtils; /** - * Simple test entity for use with caching tests. + * Copy of the shared {@code TestEntity}: necessary + * due to issues with Gradle test fixtures and AspectJ configuration + * in the Gradle build. + * + *

Simple test entity for use with caching tests. * * @author Michael Plod */ @@ -53,5 +57,4 @@ public boolean equals(Object obj) { } return false; } - } diff --git a/spring-aspects/src/test/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspectTests.java b/spring-aspects/src/test/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspectTests.java index 62dceafaede3..2f7ad0f5b6f0 100644 --- a/spring-aspects/src/test/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspectTests.java +++ b/spring-aspects/src/test/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspectTests.java @@ -30,15 +30,15 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.testfixture.EnabledForTestGroups; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import org.springframework.tests.EnabledForTestGroups; import org.springframework.util.ReflectionUtils; import org.springframework.util.concurrent.ListenableFuture; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestGroup.PERFORMANCE; +import static org.springframework.core.testfixture.TestGroup.PERFORMANCE; /** * Unit tests for {@link AnnotationAsyncExecutionAspect}. diff --git a/spring-aspects/src/test/java/org/springframework/transaction/aspectj/JtaTransactionAspectsTests.java b/spring-aspects/src/test/java/org/springframework/transaction/aspectj/JtaTransactionAspectsTests.java index aa478ba43c49..e0bd918a72ea 100644 --- a/spring-aspects/src/test/java/org/springframework/transaction/aspectj/JtaTransactionAspectsTests.java +++ b/spring-aspects/src/test/java/org/springframework/transaction/aspectj/JtaTransactionAspectsTests.java @@ -27,7 +27,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; -import org.springframework.tests.transaction.CallCountingTransactionManager; +import org.springframework.transaction.testfixture.CallCountingTransactionManager; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java b/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java index 978b2e2da700..722c357d20e2 100644 --- a/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java +++ b/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java @@ -19,7 +19,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.tests.transaction.CallCountingTransactionManager; +import org.springframework.transaction.testfixture.CallCountingTransactionManager; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-aspects/src/test/resources/org/springframework/cache/config/annotation-cache-aspectj.xml b/spring-aspects/src/test/resources/org/springframework/cache/config/annotation-cache-aspectj.xml index 1ff47150738c..1a283f6f6d83 100644 --- a/spring-aspects/src/test/resources/org/springframework/cache/config/annotation-cache-aspectj.xml +++ b/spring-aspects/src/test/resources/org/springframework/cache/config/annotation-cache-aspectj.xml @@ -22,7 +22,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/spring-beans/spring-beans.gradle b/spring-beans/spring-beans.gradle index d19807870b50..71dac23e74f1 100644 --- a/spring-beans/spring-beans.gradle +++ b/spring-beans/spring-beans.gradle @@ -10,7 +10,10 @@ dependencies { optional("org.codehaus.groovy:groovy-xml") optional("org.jetbrains.kotlin:kotlin-reflect") optional("org.jetbrains.kotlin:kotlin-stdlib") - testCompile("org.apache.tomcat.embed:tomcat-embed-core") + testCompile(testFixtures(project(":spring-core"))) + testCompile("javax.annotation:javax.annotation-api") + testFixturesApi("org.junit.jupiter:junit-jupiter-api") + testFixturesImplementation("org.assertj:assertj-core") } // This module does joint compilation for Java and Groovy code with the compileGroovy task. @@ -22,6 +25,7 @@ sourceSets { compileGroovy { sourceCompatibility = 1.8 targetCompatibility = 1.8 + options.compilerArgs += "-Werror" } // This module also builds Kotlin code and the compileKotlin task naturally depends on diff --git a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java index e079a489002e..b56ec6b9533b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -115,7 +115,7 @@ protected AbstractNestablePropertyAccessor(boolean registerDefaultEditors) { /** * Create a new accessor for the given object. - * @param object object wrapped by this accessor + * @param object the object wrapped by this accessor */ protected AbstractNestablePropertyAccessor(Object object) { registerDefaultEditors(); @@ -134,7 +134,7 @@ protected AbstractNestablePropertyAccessor(Class clazz) { /** * Create a new accessor for the given object, * registering a nested path that the object is in. - * @param object object wrapped by this accessor + * @param object the object wrapped by this accessor * @param nestedPath the nested path of the object * @param rootObject the root object at the top of the path */ @@ -146,7 +146,7 @@ protected AbstractNestablePropertyAccessor(Object object, String nestedPath, Obj /** * Create a new accessor for the given object, * registering a nested path that the object is in. - * @param object object wrapped by this accessor + * @param object the object wrapped by this accessor * @param nestedPath the nested path of the object * @param parent the containing accessor (must not be {@code null}) */ @@ -305,8 +305,10 @@ private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) Class componentType = propValue.getClass().getComponentType(); Object newArray = Array.newInstance(componentType, arrayIndex + 1); System.arraycopy(propValue, 0, newArray, 0, length); - setPropertyValue(tokens.actualName, newArray); - propValue = getPropertyValue(tokens.actualName); + int lastKeyIndex = tokens.canonicalName.lastIndexOf('['); + String propName = tokens.canonicalName.substring(0, lastKeyIndex); + setPropertyValue(propName, newArray); + propValue = getPropertyValue(propName); } Array.set(propValue, arrayIndex, convertedValue); } @@ -422,9 +424,12 @@ private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) } return; } - else { - throw createNotWritablePropertyException(tokens.canonicalName); + if (this.suppressNotWritablePropertyException) { + // Optimization for common ignoreUnknown=true scenario since the + // exception would be caught and swallowed higher up anyway... + return; } + throw createNotWritablePropertyException(tokens.canonicalName); } Object oldValue = null; @@ -737,7 +742,7 @@ protected PropertyHandler getPropertyHandler(String propertyName) throws BeansEx /** * Create a new nested property accessor instance. * Can be overridden in subclasses to create a PropertyAccessor subclass. - * @param object object wrapped by this PropertyAccessor + * @param object the object wrapped by this PropertyAccessor * @param nestedPath the nested path of the object * @return the nested PropertyAccessor instance */ @@ -806,7 +811,6 @@ protected String getFinalPath(AbstractNestablePropertyAccessor pa, String nested * @param propertyPath property path, which may be nested * @return a property accessor for the target bean */ - @SuppressWarnings("unchecked") // avoid nested generic protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) { int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath); // Handle nested properties recursively. diff --git a/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java index cd2e7e516042..1d6b5f48eab9 100644 --- a/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,8 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl private boolean autoGrowNestedPaths = false; + boolean suppressNotWritablePropertyException = false; + @Override public void setExtractOldValueForEditor(boolean extractOldValueForEditor) { @@ -89,30 +91,41 @@ public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean List propertyAccessExceptions = null; List propertyValues = (pvs instanceof MutablePropertyValues ? ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues())); - for (PropertyValue pv : propertyValues) { - try { - // This method may throw any BeansException, which won't be caught + + if (ignoreUnknown) { + this.suppressNotWritablePropertyException = true; + } + try { + for (PropertyValue pv : propertyValues) { + // setPropertyValue may throw any BeansException, which won't be caught // here, if there is a critical failure such as no matching field. // We can attempt to deal only with less serious exceptions. - setPropertyValue(pv); - } - catch (NotWritablePropertyException ex) { - if (!ignoreUnknown) { - throw ex; + try { + setPropertyValue(pv); } - // Otherwise, just ignore it and continue... - } - catch (NullValueInNestedPathException ex) { - if (!ignoreInvalid) { - throw ex; + catch (NotWritablePropertyException ex) { + if (!ignoreUnknown) { + throw ex; + } + // Otherwise, just ignore it and continue... } - // Otherwise, just ignore it and continue... - } - catch (PropertyAccessException ex) { - if (propertyAccessExceptions == null) { - propertyAccessExceptions = new ArrayList<>(); + catch (NullValueInNestedPathException ex) { + if (!ignoreInvalid) { + throw ex; + } + // Otherwise, just ignore it and continue... + } + catch (PropertyAccessException ex) { + if (propertyAccessExceptions == null) { + propertyAccessExceptions = new ArrayList<>(); + } + propertyAccessExceptions.add(ex); } - propertyAccessExceptions.add(ex); + } + } + finally { + if (ignoreUnknown) { + this.suppressNotWritablePropertyException = false; } } diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java index 3e0ef30ecd98..df4955eb6ba4 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,7 @@ import kotlin.reflect.KFunction; import kotlin.reflect.KParameter; import kotlin.reflect.full.KClasses; +import kotlin.reflect.jvm.KCallablesJvm; import kotlin.reflect.jvm.ReflectJvmMapping; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -55,8 +56,11 @@ * Static convenience methods for JavaBeans: for instantiating beans, * checking bean property types, copying bean properties, etc. * - *

Mainly for use within the framework, but to some degree also - * useful for application classes. + *

Mainly for internal use within the framework, but to some degree also + * useful for application classes. Consider + * Apache Commons BeanUtils, + * BULL - Bean Utils Light Library, + * or similar third-party frameworks for more comprehensive bean utilities. * * @author Rod Johnson * @author Juergen Hoeller @@ -79,7 +83,10 @@ public abstract class BeanUtils { values.put(byte.class, (byte) 0); values.put(short.class, (short) 0); values.put(int.class, 0); - values.put(long.class, (long) 0); + values.put(long.class, 0L); + values.put(float.class, 0F); + values.put(double.class, 0D); + values.put(char.class, '\0'); DEFAULT_TYPE_VALUES = Collections.unmodifiableMap(values); } @@ -223,7 +230,6 @@ public static T instantiateClass(Constructor ctor, Object... args) throws * @since 5.0 * @see Kotlin docs */ - @SuppressWarnings("unchecked") @Nullable public static Constructor findPrimaryConstructor(Class clazz) { Assert.notNull(clazz, "Class must not be null"); @@ -438,8 +444,7 @@ else if (startParen == -1) { * @throws BeansException if PropertyDescriptor look fails */ public static PropertyDescriptor[] getPropertyDescriptors(Class clazz) throws BeansException { - CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz); - return cr.getPropertyDescriptors(); + return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptors(); } /** @@ -450,11 +455,8 @@ public static PropertyDescriptor[] getPropertyDescriptors(Class clazz) throws * @throws BeansException if PropertyDescriptor lookup fails */ @Nullable - public static PropertyDescriptor getPropertyDescriptor(Class clazz, String propertyName) - throws BeansException { - - CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz); - return cr.getPropertyDescriptor(propertyName); + public static PropertyDescriptor getPropertyDescriptor(Class clazz, String propertyName) throws BeansException { + return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptor(propertyName); } /** @@ -507,6 +509,7 @@ public static PropertyEditor findEditorByConvention(@Nullable Class targetTyp if (targetType == null || targetType.isArray() || unknownEditorTypes.contains(targetType)) { return null; } + ClassLoader cl = targetType.getClassLoader(); if (cl == null) { try { @@ -523,27 +526,34 @@ public static PropertyEditor findEditorByConvention(@Nullable Class targetTyp return null; } } - String editorName = targetType.getName() + "Editor"; + + String targetTypeName = targetType.getName(); + String editorName = targetTypeName + "Editor"; try { Class editorClass = cl.loadClass(editorName); - if (!PropertyEditor.class.isAssignableFrom(editorClass)) { - if (logger.isInfoEnabled()) { - logger.info("Editor class [" + editorName + - "] does not implement [java.beans.PropertyEditor] interface"); + if (editorClass != null) { + if (!PropertyEditor.class.isAssignableFrom(editorClass)) { + if (logger.isInfoEnabled()) { + logger.info("Editor class [" + editorName + + "] does not implement [java.beans.PropertyEditor] interface"); + } + unknownEditorTypes.add(targetType); + return null; } - unknownEditorTypes.add(targetType); - return null; + return (PropertyEditor) instantiateClass(editorClass); } - return (PropertyEditor) instantiateClass(editorClass); + // Misbehaving ClassLoader returned null instead of ClassNotFoundException + // - fall back to unknown editor type registration below } catch (ClassNotFoundException ex) { - if (logger.isTraceEnabled()) { - logger.trace("No property editor [" + editorName + "] found for type " + - targetType.getName() + " according to 'Editor' suffix convention"); - } - unknownEditorTypes.add(targetType); - return null; + // Ignore - fall back to unknown editor type registration below } + if (logger.isTraceEnabled()) { + logger.trace("No property editor [" + editorName + "] found for type " + + targetTypeName + " according to 'Editor' suffix convention"); + } + unknownEditorTypes.add(targetType); + return null; } /** @@ -776,6 +786,11 @@ public static T instantiateClass(Constructor ctor, Object... args) if (kotlinConstructor == null) { return ctor.newInstance(args); } + + if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers()))) { + KCallablesJvm.setAccessible(kotlinConstructor, true); + } + List parameters = kotlinConstructor.getParameters(); Map argParameters = new HashMap<>(parameters.size()); Assert.isTrue(args.length <= parameters.size(), diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java b/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java index 4baa57cb7bdb..c2fb1aca6f71 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -97,7 +97,7 @@ public BeanWrapperImpl(boolean registerDefaultEditors) { /** * Create a new BeanWrapperImpl for the given object. - * @param object object wrapped by this BeanWrapper + * @param object the object wrapped by this BeanWrapper */ public BeanWrapperImpl(Object object) { super(object); @@ -114,7 +114,7 @@ public BeanWrapperImpl(Class clazz) { /** * Create a new BeanWrapperImpl for the given object, * registering a nested path that the object is in. - * @param object object wrapped by this BeanWrapper + * @param object the object wrapped by this BeanWrapper * @param nestedPath the nested path of the object * @param rootObject the root object at the top of the path */ @@ -125,7 +125,7 @@ public BeanWrapperImpl(Object object, String nestedPath, Object rootObject) { /** * Create a new BeanWrapperImpl for the given object, * registering a nested path that the object is in. - * @param object object wrapped by this BeanWrapper + * @param object the object wrapped by this BeanWrapper * @param nestedPath the nested path of the object * @param parent the containing BeanWrapper (must not be {@code null}) */ @@ -289,15 +289,15 @@ public TypeDescriptor nested(int level) { @Override @Nullable public Object getValue() throws Exception { - final Method readMethod = this.pd.getReadMethod(); + Method readMethod = this.pd.getReadMethod(); if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction) () -> { ReflectionUtils.makeAccessible(readMethod); return null; }); try { - return AccessController.doPrivileged((PrivilegedExceptionAction) () -> - readMethod.invoke(getWrappedInstance(), (Object[]) null), acc); + return AccessController.doPrivileged((PrivilegedExceptionAction) + () -> readMethod.invoke(getWrappedInstance(), (Object[]) null), acc); } catch (PrivilegedActionException pae) { throw pae.getException(); @@ -310,8 +310,8 @@ public Object getValue() throws Exception { } @Override - public void setValue(final @Nullable Object value) throws Exception { - final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ? + public void setValue(@Nullable Object value) throws Exception { + Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ? ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() : this.pd.getWriteMethod()); if (System.getSecurityManager() != null) { @@ -320,8 +320,8 @@ public void setValue(final @Nullable Object value) throws Exception { return null; }); try { - AccessController.doPrivileged((PrivilegedExceptionAction) () -> - writeMethod.invoke(getWrappedInstance(), value), acc); + AccessController.doPrivileged((PrivilegedExceptionAction) + () -> writeMethod.invoke(getWrappedInstance(), value), acc); } catch (PrivilegedActionException ex) { throw ex.getException(); diff --git a/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java b/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java index ca14d6995d20..c66fd04b2171 100644 --- a/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java +++ b/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; +import java.security.ProtectionDomain; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -43,9 +44,9 @@ * Internal class that caches JavaBeans {@link java.beans.PropertyDescriptor} * information for a Java class. Not intended for direct use by application code. * - *

Necessary for own caching of descriptors within the application's - * ClassLoader, rather than rely on the JDK's system-wide BeanInfo cache - * (in order to avoid leaks on ClassLoader shutdown). + *

Necessary for Spring's own caching of bean descriptors within the application + * {@link ClassLoader}, rather than relying on the JDK's system-wide {@link BeanInfo} + * cache (in order to avoid leaks on individual application shutdown in a shared JVM). * *

Information is cached statically, so we don't need to create new * objects of this class for every JavaBean we manipulate. Hence, this class @@ -92,12 +93,14 @@ public final class CachedIntrospectionResults { */ public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore"; + private static final PropertyDescriptor[] EMPTY_PROPERTY_DESCRIPTOR_ARRAY = {}; + private static final boolean shouldIntrospectorIgnoreBeaninfoClasses = SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME); /** Stores the BeanInfoFactory instances. */ - private static List beanInfoFactories = SpringFactoriesLoader.loadFactories( + private static final List beanInfoFactories = SpringFactoriesLoader.loadFactories( BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader()); private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class); @@ -163,7 +166,6 @@ public static void clearClassLoader(@Nullable ClassLoader classLoader) { * @return the corresponding CachedIntrospectionResults * @throws BeansException in case of introspection failure */ - @SuppressWarnings("unchecked") static CachedIntrospectionResults forClass(Class beanClass) throws BeansException { CachedIntrospectionResults results = strongClassCache.get(beanClass); if (results != null) { @@ -254,7 +256,7 @@ private static BeanInfo getBeanInfo(Class beanClass) throws IntrospectionExce private final BeanInfo beanInfo; /** PropertyDescriptor objects keyed by property name String. */ - private final Map propertyDescriptorCache; + private final Map propertyDescriptors; /** TypeDescriptor objects keyed by PropertyDescriptor. */ private final ConcurrentMap typeDescriptorCache; @@ -275,14 +277,18 @@ private CachedIntrospectionResults(Class beanClass) throws BeansException { if (logger.isTraceEnabled()) { logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]"); } - this.propertyDescriptorCache = new LinkedHashMap<>(); + this.propertyDescriptors = new LinkedHashMap<>(); // This call is slow so we do it once. PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors(); for (PropertyDescriptor pd : pds) { - if (Class.class == beanClass && - ("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) { - // Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those + if (Class.class == beanClass && (!"name".equals(pd.getName()) && !pd.getName().endsWith("Name"))) { + // Only allow all name variants of Class properties + continue; + } + if (pd.getPropertyType() != null && (ClassLoader.class.isAssignableFrom(pd.getPropertyType()) + || ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) { + // Ignore ClassLoader and ProtectionDomain types - nobody needs to bind to those continue; } if (logger.isTraceEnabled()) { @@ -292,7 +298,7 @@ private CachedIntrospectionResults(Class beanClass) throws BeansException { "; editor [" + pd.getPropertyEditorClass().getName() + "]" : "")); } pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd); - this.propertyDescriptorCache.put(pd.getName(), pd); + this.propertyDescriptors.put(pd.getName(), pd); } // Explicitly check implemented interfaces for setter/getter methods as well, @@ -314,13 +320,18 @@ private void introspectInterfaces(Class beanClass, Class currClass) throws for (Class ifc : currClass.getInterfaces()) { if (!ClassUtils.isJavaLanguageInterface(ifc)) { for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) { - PropertyDescriptor existingPd = this.propertyDescriptorCache.get(pd.getName()); + PropertyDescriptor existingPd = this.propertyDescriptors.get(pd.getName()); if (existingPd == null || (existingPd.getReadMethod() == null && pd.getReadMethod() != null)) { // GenericTypeAwarePropertyDescriptor leniently resolves a set* write method // against a declared read method, so we prefer read method descriptors here. pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd); - this.propertyDescriptorCache.put(pd.getName(), pd); + if (pd.getPropertyType() != null && (ClassLoader.class.isAssignableFrom(pd.getPropertyType()) + || ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) { + // Ignore ClassLoader and ProtectionDomain types - nobody needs to bind to those + continue; + } + this.propertyDescriptors.put(pd.getName(), pd); } } introspectInterfaces(ifc, ifc); @@ -339,27 +350,19 @@ Class getBeanClass() { @Nullable PropertyDescriptor getPropertyDescriptor(String name) { - PropertyDescriptor pd = this.propertyDescriptorCache.get(name); + PropertyDescriptor pd = this.propertyDescriptors.get(name); if (pd == null && StringUtils.hasLength(name)) { // Same lenient fallback checking as in Property... - pd = this.propertyDescriptorCache.get(StringUtils.uncapitalize(name)); + pd = this.propertyDescriptors.get(StringUtils.uncapitalize(name)); if (pd == null) { - pd = this.propertyDescriptorCache.get(StringUtils.capitalize(name)); + pd = this.propertyDescriptors.get(StringUtils.capitalize(name)); } } - return (pd == null || pd instanceof GenericTypeAwarePropertyDescriptor ? pd : - buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd)); + return pd; } PropertyDescriptor[] getPropertyDescriptors() { - PropertyDescriptor[] pds = new PropertyDescriptor[this.propertyDescriptorCache.size()]; - int i = 0; - for (PropertyDescriptor pd : this.propertyDescriptorCache.values()) { - pds[i] = (pd instanceof GenericTypeAwarePropertyDescriptor ? pd : - buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd)); - i++; - } - return pds; + return this.propertyDescriptors.values().toArray(EMPTY_PROPERTY_DESCRIPTOR_ARRAY); } private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class beanClass, PropertyDescriptor pd) { diff --git a/spring-beans/src/main/java/org/springframework/beans/DirectFieldAccessor.java b/spring-beans/src/main/java/org/springframework/beans/DirectFieldAccessor.java index f526ab3cdcf1..a98c6eb41b03 100644 --- a/spring-beans/src/main/java/org/springframework/beans/DirectFieldAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/DirectFieldAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,7 +52,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor { /** * Create a new DirectFieldAccessor for the given object. - * @param object object wrapped by this DirectFieldAccessor + * @param object the object wrapped by this DirectFieldAccessor */ public DirectFieldAccessor(Object object) { super(object); @@ -61,7 +61,7 @@ public DirectFieldAccessor(Object object) { /** * Create a new DirectFieldAccessor for the given object, * registering a nested path that the object is in. - * @param object object wrapped by this DirectFieldAccessor + * @param object the object wrapped by this DirectFieldAccessor * @param nestedPath the nested path of the object * @param parent the containing DirectFieldAccessor (must not be {@code null}) */ @@ -92,8 +92,7 @@ protected DirectFieldAccessor newNestedPropertyAccessor(Object object, String ne @Override protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) { PropertyMatches matches = PropertyMatches.forField(propertyName, getRootClass()); - throw new NotWritablePropertyException( - getRootClass(), getNestedPath() + propertyName, + throw new NotWritablePropertyException(getRootClass(), getNestedPath() + propertyName, matches.buildErrorMessage(), matches.getPossibleMatches()); } diff --git a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java index e8952301f28f..21ce57cf6add 100644 --- a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java +++ b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,8 +41,8 @@ /** * Decorator for a standard {@link BeanInfo} object, e.g. as created by - * {@link Introspector#getBeanInfo(Class)}, designed to discover and register static - * and/or non-void returning setter methods. For example: + * {@link Introspector#getBeanInfo(Class)}, designed to discover and register + * static and/or non-void returning setter methods. For example: * *

  * public class Bean {
@@ -145,11 +145,10 @@ private List findCandidateWriteMethods(MethodDescriptor[] methodDescript
 
 	public static boolean isCandidateWriteMethod(Method method) {
 		String methodName = method.getName();
-		Class[] parameterTypes = method.getParameterTypes();
-		int nParams = parameterTypes.length;
+		int nParams = method.getParameterCount();
 		return (methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) &&
 				(!void.class.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) &&
-				(nParams == 1 || (nParams == 2 && int.class == parameterTypes[0])));
+				(nParams == 1 || (nParams == 2 && int.class == method.getParameterTypes()[0])));
 	}
 
 	private void handleCandidateWriteMethod(Method method) throws IntrospectionException {
@@ -209,7 +208,7 @@ private PropertyDescriptor findExistingPropertyDescriptor(String propertyName, C
 	}
 
 	private String propertyNameFor(Method method) {
-		return Introspector.decapitalize(method.getName().substring(3, method.getName().length()));
+		return Introspector.decapitalize(method.getName().substring(3));
 	}
 
 
@@ -488,7 +487,7 @@ public void setPropertyEditorClass(@Nullable Class propertyEditorClass) {
 		}
 
 		/*
-		 * See java.beans.IndexedPropertyDescriptor#equals(java.lang.Object)
+		 * See java.beans.IndexedPropertyDescriptor#equals
 		 */
 		@Override
 		public boolean equals(@Nullable Object other) {
@@ -535,11 +534,13 @@ static class PropertyDescriptorComparator implements Comparator propertyType;
 
+	@Nullable
 	private final Class propertyEditorClass;
 
 
 	public GenericTypeAwarePropertyDescriptor(Class beanClass, String propertyName,
-			@Nullable Method readMethod, @Nullable Method writeMethod, Class propertyEditorClass)
-			throws IntrospectionException {
+			@Nullable Method readMethod, @Nullable Method writeMethod,
+			@Nullable Class propertyEditorClass) throws IntrospectionException {
 
 		super(propertyName, null, null);
 		this.beanClass = beanClass;
@@ -137,7 +138,7 @@ public Method getWriteMethodForActualAccess() {
 		Set ambiguousCandidates = this.ambiguousWriteMethods;
 		if (ambiguousCandidates != null) {
 			this.ambiguousWriteMethods = null;
-			LogFactory.getLog(GenericTypeAwarePropertyDescriptor.class).warn("Invalid JavaBean property '" +
+			LogFactory.getLog(GenericTypeAwarePropertyDescriptor.class).debug("Non-unique JavaBean property '" +
 					getName() + "' being accessed! Ambiguous write methods found next to actually used [" +
 					this.writeMethod + "]: " + ambiguousCandidates);
 		}
@@ -156,6 +157,7 @@ public Class getPropertyType() {
 	}
 
 	@Override
+	@Nullable
 	public Class getPropertyEditorClass() {
 		return this.propertyEditorClass;
 	}
diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyDescriptorUtils.java b/spring-beans/src/main/java/org/springframework/beans/PropertyDescriptorUtils.java
index c5ac50cb4b42..aa9909822d18 100644
--- a/spring-beans/src/main/java/org/springframework/beans/PropertyDescriptorUtils.java
+++ b/spring-beans/src/main/java/org/springframework/beans/PropertyDescriptorUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -66,8 +66,7 @@ public static Class findPropertyType(@Nullable Method readMethod, @Nullable M
 		Class propertyType = null;
 
 		if (readMethod != null) {
-			Class[] params = readMethod.getParameterTypes();
-			if (params.length != 0) {
+			if (readMethod.getParameterCount() != 0) {
 				throw new IntrospectionException("Bad read method arg count: " + readMethod);
 			}
 			propertyType = readMethod.getReturnType();
diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java b/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java
index e73a34fb7fbe..dfd2e117d8ab 100644
--- a/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java
+++ b/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java
@@ -501,7 +501,7 @@ private void addStrippedPropertyPaths(List strippedPaths, String nestedP
 			if (endIndex != -1) {
 				String prefix = propertyPath.substring(0, startIndex);
 				String key = propertyPath.substring(startIndex, endIndex + 1);
-				String suffix = propertyPath.substring(endIndex + 1, propertyPath.length());
+				String suffix = propertyPath.substring(endIndex + 1);
 				// Strip the first key.
 				strippedPaths.add(nestedPath + prefix + suffix);
 				// Search for further keys to strip, with the first key stripped.
diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyValues.java b/spring-beans/src/main/java/org/springframework/beans/PropertyValues.java
index 6840bb9116af..b754a32a0f60 100644
--- a/spring-beans/src/main/java/org/springframework/beans/PropertyValues.java
+++ b/spring-beans/src/main/java/org/springframework/beans/PropertyValues.java
@@ -78,7 +78,7 @@ default Stream stream() {
 	/**
 	 * Return the changes since the previous PropertyValues.
 	 * Subclasses should also override {@code equals}.
-	 * @param old old property values
+	 * @param old the old property values
 	 * @return the updated or new properties.
 	 * Return empty PropertyValues if there are no changes.
 	 * @see Object#equals
diff --git a/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java b/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java
index 3177c4b20ed2..4a6f52400e8d 100644
--- a/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java
+++ b/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2021 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,10 +41,10 @@ public class TypeMismatchException extends PropertyAccessException {
 	private String propertyName;
 
 	@Nullable
-	private transient Object value;
+	private final transient Object value;
 
 	@Nullable
-	private Class requiredType;
+	private final Class requiredType;
 
 
 	/**
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
index e0b345f62290..f31c29d85170 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,7 +22,8 @@
 
 /**
  * The root interface for accessing a Spring bean container.
- * This is the basic client view of a bean container;
+ *
+ * 

This is the basic client view of a bean container; * further interfaces such as {@link ListableBeanFactory} and * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory} * are available for specific purposes. @@ -130,7 +131,7 @@ public interface BeanFactory { * Singleton or Prototype design pattern. Callers may retain references to * returned objects in the case of Singleton beans. *

Translates aliases back to the corresponding canonical bean name. - * Will ask the parent factory if the bean cannot be found in this factory instance. + *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to retrieve * @return an instance of the bean * @throws NoSuchBeanDefinitionException if there is no bean with the specified name @@ -145,7 +146,7 @@ public interface BeanFactory { * required type. This means that ClassCastException can't be thrown on casting * the result correctly, as can happen with {@link #getBean(String)}. *

Translates aliases back to the corresponding canonical bean name. - * Will ask the parent factory if the bean cannot be found in this factory instance. + *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to retrieve * @param requiredType type the bean must match; can be an interface or superclass * @return an instance of the bean @@ -258,7 +259,7 @@ public interface BeanFactory { * to a scoped bean as well. Use the {@link #isPrototype} operation to explicitly * check for independent instances. *

Translates aliases back to the corresponding canonical bean name. - * Will ask the parent factory if the bean cannot be found in this factory instance. + *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to query * @return whether this bean corresponds to a singleton instance * @throws NoSuchBeanDefinitionException if there is no bean with the given name @@ -275,7 +276,7 @@ public interface BeanFactory { * to a scoped bean as well. Use the {@link #isSingleton} operation to explicitly * check for a shared singleton instance. *

Translates aliases back to the corresponding canonical bean name. - * Will ask the parent factory if the bean cannot be found in this factory instance. + *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to query * @return whether this bean will always deliver independent instances * @throws NoSuchBeanDefinitionException if there is no bean with the given name @@ -290,7 +291,7 @@ public interface BeanFactory { * More specifically, check whether a {@link #getBean} call for the given name * would return an object that is assignable to the specified target type. *

Translates aliases back to the corresponding canonical bean name. - * Will ask the parent factory if the bean cannot be found in this factory instance. + *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to query * @param typeToMatch the type to match against (as a {@code ResolvableType}) * @return {@code true} if the bean type matches, @@ -307,7 +308,7 @@ public interface BeanFactory { * More specifically, check whether a {@link #getBean} call for the given name * would return an object that is assignable to the specified target type. *

Translates aliases back to the corresponding canonical bean name. - * Will ask the parent factory if the bean cannot be found in this factory instance. + *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to query * @param typeToMatch the type to match against (as a {@code Class}) * @return {@code true} if the bean type matches, @@ -326,7 +327,7 @@ public interface BeanFactory { * as exposed by {@link FactoryBean#getObjectType()}. This may lead to the initialization * of a previously uninitialized {@code FactoryBean} (see {@link #getType(String, boolean)}). *

Translates aliases back to the corresponding canonical bean name. - * Will ask the parent factory if the bean cannot be found in this factory instance. + *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to query * @return the type of the bean, or {@code null} if not determinable * @throws NoSuchBeanDefinitionException if there is no bean with the given name @@ -345,7 +346,7 @@ public interface BeanFactory { * {@code allowFactoryBeanInit} flag, this may lead to the initialization of a previously * uninitialized {@code FactoryBean} if no early type information is available. *

Translates aliases back to the corresponding canonical bean name. - * Will ask the parent factory if the bean cannot be found in this factory instance. + *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to query * @param allowFactoryBeanInit whether a {@code FactoryBean} may get initialized * just for the purpose of determining its object type @@ -360,7 +361,7 @@ public interface BeanFactory { /** * Return the aliases for the given bean name, if any. - * All of those aliases point to the same bean when used in a {@link #getBean} call. + *

All of those aliases point to the same bean when used in a {@link #getBean} call. *

If the given name is an alias, the corresponding original bean name * and other aliases (if any) will be returned, with the original bean name * being the first element in the array. diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/FactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/FactoryBean.java index c20df830a433..224563cc7749 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/FactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/FactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,10 +39,16 @@ * *

{@code FactoryBean} is a programmatic contract. Implementations are not * supposed to rely on annotation-driven injection or other reflective facilities. - * {@link #getObjectType()} {@link #getObject()} invocations may arrive early in - * the bootstrap process, even ahead of any post-processor setup. If you need access + * {@link #getObjectType()} {@link #getObject()} invocations may arrive early in the + * bootstrap process, even ahead of any post-processor setup. If you need access to * other beans, implement {@link BeanFactoryAware} and obtain them programmatically. * + *

The container is only responsible for managing the lifecycle of the FactoryBean + * instance, not the lifecycle of the objects created by the FactoryBean. Therefore, + * a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()} + * will not be called automatically. Instead, a FactoryBean should implement + * {@link DisposableBean} and delegate any such close call to the underlying object. + * *

Finally, FactoryBean objects participate in the containing BeanFactory's * synchronization of bean creation. There is usually no need for internal * synchronization other than for purposes of lazy initialization within the diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java index 09f0f5dade56..4df284c3083a 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,7 @@ * They will ignore any singleton beans that have been registered by other means like * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}'s * {@code registerSingleton} method, with the exception of - * {@code getBeanNamesOfType} and {@code getBeansOfType} which will check + * {@code getBeanNamesForType} and {@code getBeansOfType} which will check * such manually registered singletons too. Of course, BeanFactory's {@code getBean} * does allow transparent access to such special beans as well. However, in typical * scenarios, all beans will be defined by external bean definitions anyway, so most diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolver.java index a0e05da517b2..b3550404c5c5 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolver.java @@ -56,7 +56,7 @@ protected BeanWiringInfo buildWiringInfo(Object beanInstance, Configurable annot // Autowiring by name or by type return new BeanWiringInfo(annotation.autowire().value(), annotation.dependencyCheck()); } - else if (!"".equals(annotation.value())) { + else if (!annotation.value().isEmpty()) { // Explicitly specified bean name for bean definition to take property values from return new BeanWiringInfo(annotation.value(), false); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java index 36e91744666b..242fddbad8e1 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java @@ -36,9 +36,11 @@ * annotation, they will be considered as candidates for autowiring. The constructor * with the greatest number of dependencies that can be satisfied by matching beans * in the Spring container will be chosen. If none of the candidates can be satisfied, - * then a primary/default constructor (if present) will be used. If a class only - * declares a single constructor to begin with, it will always be used, even if not - * annotated. An annotated constructor does not have to be public. + * then a primary/default constructor (if present) will be used. Similarly, if a + * class declares multiple constructors but none of them is annotated with + * {@code @Autowired}, then a primary/default constructor (if present) will be used. + * If a class only declares a single constructor to begin with, it will always be used, + * even if not annotated. An annotated constructor does not have to be public. * *

Autowired Fields

*

Fields are injected right after construction of a bean, before any config methods diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 4b2d208a32e2..8e6bbcdff717 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -153,7 +153,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean /** * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's - * standard {@link Autowired @Autowired} annotation. + * standard {@link Autowired @Autowired} and {@link Value @Value} annotations. *

Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation, * if available. */ @@ -174,9 +174,10 @@ public AutowiredAnnotationBeanPostProcessor() { /** * Set the 'autowired' annotation type, to be used on constructors, fields, - * setter methods and arbitrary config methods. - *

The default autowired annotation type is the Spring-provided {@link Autowired} - * annotation, as well as {@link Value}. + * setter methods, and arbitrary config methods. + *

The default autowired annotation types are the Spring-provided + * {@link Autowired @Autowired} and {@link Value @Value} annotations as well + * as JSR-330's {@link javax.inject.Inject @Inject} annotation, if available. *

This setter property exists so that developers can provide their own * (non-Spring-specific) annotation type to indicate that a member is supposed * to be autowired. @@ -189,9 +190,10 @@ public void setAutowiredAnnotationType(Class autowiredAnno /** * Set the 'autowired' annotation types, to be used on constructors, fields, - * setter methods and arbitrary config methods. - *

The default autowired annotation type is the Spring-provided {@link Autowired} - * annotation, as well as {@link Value}. + * setter methods, and arbitrary config methods. + *

The default autowired annotation types are the Spring-provided + * {@link Autowired @Autowired} and {@link Value @Value} annotations as well + * as JSR-330's {@link javax.inject.Inject @Inject} annotation, if available. *

This setter property exists so that developers can provide their own * (non-Spring-specific) annotation types to indicate that a member is supposed * to be autowired. @@ -203,7 +205,7 @@ public void setAutowiredAnnotationTypes(Set> autowir } /** - * Set the name of a parameter of the annotation that specifies whether it is required. + * Set the name of an attribute of the annotation that specifies whether it is required. * @see #setRequiredParameterValue(boolean) */ public void setRequiredParameterName(String requiredParameterName) { @@ -211,7 +213,7 @@ public void setRequiredParameterName(String requiredParameterName) { } /** - * Set the boolean value that marks a dependency as required + * Set the boolean value that marks a dependency as required. *

For example if using 'required=true' (the default), this value should be * {@code true}; but if using 'optional=false', this value should be {@code false}. * @see #setRequiredParameterName(String) @@ -415,9 +417,11 @@ public PropertyValues postProcessPropertyValues( /** * 'Native' processing method for direct calls with an arbitrary target instance, - * resolving all of its fields and methods which are annotated with {@code @Autowired}. + * resolving all of its fields and methods which are annotated with one of the + * configured 'autowired' annotation types. * @param bean the target instance to process * @throws BeanCreationException if autowiring failed + * @see #setAutowiredAnnotationTypes(Set) */ public void processInjection(Object bean) throws BeanCreationException { Class clazz = bean.getClass(); @@ -455,7 +459,7 @@ private InjectionMetadata findAutowiringMetadata(String beanName, Class clazz return metadata; } - private InjectionMetadata buildAutowiringMetadata(final Class clazz) { + private InjectionMetadata buildAutowiringMetadata(Class clazz) { if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { return InjectionMetadata.EMPTY; } @@ -609,7 +613,7 @@ private class AutowiredFieldElement extends InjectionMetadata.InjectedElement { private final boolean required; - private volatile boolean cached = false; + private volatile boolean cached; @Nullable private volatile Object cachedFieldValue; @@ -624,46 +628,58 @@ protected void inject(Object bean, @Nullable String beanName, @Nullable Property Field field = (Field) this.member; Object value; if (this.cached) { - value = resolvedCachedArgument(beanName, this.cachedFieldValue); - } - else { - DependencyDescriptor desc = new DependencyDescriptor(field, this.required); - desc.setContainingClass(bean.getClass()); - Set autowiredBeanNames = new LinkedHashSet<>(1); - Assert.state(beanFactory != null, "No BeanFactory available"); - TypeConverter typeConverter = beanFactory.getTypeConverter(); try { - value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); + value = resolvedCachedArgument(beanName, this.cachedFieldValue); } - catch (BeansException ex) { - throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); - } - synchronized (this) { - if (!this.cached) { - if (value != null || this.required) { - this.cachedFieldValue = desc; - registerDependentBeans(beanName, autowiredBeanNames); - if (autowiredBeanNames.size() == 1) { - String autowiredBeanName = autowiredBeanNames.iterator().next(); - if (beanFactory.containsBean(autowiredBeanName) && - beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { - this.cachedFieldValue = new ShortcutDependencyDescriptor( - desc, autowiredBeanName, field.getType()); - } - } - } - else { - this.cachedFieldValue = null; - } - this.cached = true; - } + catch (NoSuchBeanDefinitionException ex) { + // Unexpected removal of target bean for cached argument -> re-resolve + value = resolveFieldValue(field, bean, beanName); } } + else { + value = resolveFieldValue(field, bean, beanName); + } if (value != null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); } } + + @Nullable + private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) { + DependencyDescriptor desc = new DependencyDescriptor(field, this.required); + desc.setContainingClass(bean.getClass()); + Set autowiredBeanNames = new LinkedHashSet<>(1); + Assert.state(beanFactory != null, "No BeanFactory available"); + TypeConverter typeConverter = beanFactory.getTypeConverter(); + Object value; + try { + value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); + } + catch (BeansException ex) { + throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); + } + synchronized (this) { + if (!this.cached) { + Object cachedFieldValue = null; + if (value != null || this.required) { + cachedFieldValue = desc; + registerDependentBeans(beanName, autowiredBeanNames); + if (autowiredBeanNames.size() == 1) { + String autowiredBeanName = autowiredBeanNames.iterator().next(); + if (beanFactory.containsBean(autowiredBeanName) && + beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { + cachedFieldValue = new ShortcutDependencyDescriptor( + desc, autowiredBeanName, field.getType()); + } + } + } + this.cachedFieldValue = cachedFieldValue; + this.cached = true; + } + } + return value; + } } @@ -674,7 +690,7 @@ private class AutowiredMethodElement extends InjectionMetadata.InjectedElement { private final boolean required; - private volatile boolean cached = false; + private volatile boolean cached; @Nullable private volatile Object[] cachedMethodArguments; @@ -692,58 +708,17 @@ protected void inject(Object bean, @Nullable String beanName, @Nullable Property Method method = (Method) this.member; Object[] arguments; if (this.cached) { - // Shortcut for avoiding synchronization... - arguments = resolveCachedArguments(beanName); - } - else { - Class[] paramTypes = method.getParameterTypes(); - arguments = new Object[paramTypes.length]; - DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length]; - Set autowiredBeans = new LinkedHashSet<>(paramTypes.length); - Assert.state(beanFactory != null, "No BeanFactory available"); - TypeConverter typeConverter = beanFactory.getTypeConverter(); - for (int i = 0; i < arguments.length; i++) { - MethodParameter methodParam = new MethodParameter(method, i); - DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required); - currDesc.setContainingClass(bean.getClass()); - descriptors[i] = currDesc; - try { - Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter); - if (arg == null && !this.required) { - arguments = null; - break; - } - arguments[i] = arg; - } - catch (BeansException ex) { - throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex); - } + try { + arguments = resolveCachedArguments(beanName); } - synchronized (this) { - if (!this.cached) { - if (arguments != null) { - DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length); - registerDependentBeans(beanName, autowiredBeans); - if (autowiredBeans.size() == paramTypes.length) { - Iterator it = autowiredBeans.iterator(); - for (int i = 0; i < paramTypes.length; i++) { - String autowiredBeanName = it.next(); - if (beanFactory.containsBean(autowiredBeanName) && - beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) { - cachedMethodArguments[i] = new ShortcutDependencyDescriptor( - descriptors[i], autowiredBeanName, paramTypes[i]); - } - } - } - this.cachedMethodArguments = cachedMethodArguments; - } - else { - this.cachedMethodArguments = null; - } - this.cached = true; - } + catch (NoSuchBeanDefinitionException ex) { + // Unexpected removal of target bean for cached argument -> re-resolve + arguments = resolveMethodArguments(method, bean, beanName); } } + else { + arguments = resolveMethodArguments(method, bean, beanName); + } if (arguments != null) { try { ReflectionUtils.makeAccessible(method); @@ -767,6 +742,59 @@ private Object[] resolveCachedArguments(@Nullable String beanName) { } return arguments; } + + @Nullable + private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) { + int argumentCount = method.getParameterCount(); + Object[] arguments = new Object[argumentCount]; + DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount]; + Set autowiredBeans = new LinkedHashSet<>(argumentCount); + Assert.state(beanFactory != null, "No BeanFactory available"); + TypeConverter typeConverter = beanFactory.getTypeConverter(); + for (int i = 0; i < arguments.length; i++) { + MethodParameter methodParam = new MethodParameter(method, i); + DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required); + currDesc.setContainingClass(bean.getClass()); + descriptors[i] = currDesc; + try { + Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter); + if (arg == null && !this.required) { + arguments = null; + break; + } + arguments[i] = arg; + } + catch (BeansException ex) { + throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex); + } + } + synchronized (this) { + if (!this.cached) { + if (arguments != null) { + DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length); + registerDependentBeans(beanName, autowiredBeans); + if (autowiredBeans.size() == argumentCount) { + Iterator it = autowiredBeans.iterator(); + Class[] paramTypes = method.getParameterTypes(); + for (int i = 0; i < paramTypes.length; i++) { + String autowiredBeanName = it.next(); + if (beanFactory.containsBean(autowiredBeanName) && + beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) { + cachedMethodArguments[i] = new ShortcutDependencyDescriptor( + descriptors[i], autowiredBeanName, paramTypes[i]); + } + } + } + this.cachedMethodArguments = cachedMethodArguments; + } + else { + this.cachedMethodArguments = null; + } + this.cached = true; + } + } + return arguments; + } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java index 1d1fbd77cb72..f7dcb8d18cf1 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,9 +26,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.support.RootBeanDefinition; @@ -53,6 +50,10 @@ public class InjectionMetadata { * @since 5.2 */ public static final InjectionMetadata EMPTY = new InjectionMetadata(Object.class, Collections.emptyList()) { + @Override + protected boolean needsRefresh(Class clazz) { + return false; + } @Override public void checkConfigMembers(RootBeanDefinition beanDefinition) { } @@ -65,8 +66,6 @@ public void clear(@Nullable PropertyValues pvs) { }; - private static final Log logger = LogFactory.getLog(InjectionMetadata.class); - private final Class targetClass; private final Collection injectedElements; @@ -89,6 +88,16 @@ public InjectionMetadata(Class targetClass, Collection eleme } + /** + * Determine whether this metadata instance needs to be refreshed. + * @param clazz the current target class + * @return {@code true} indicating a refresh, {@code false} otherwise + * @since 5.2.4 + */ + protected boolean needsRefresh(Class clazz) { + return this.targetClass != clazz; + } + public void checkConfigMembers(RootBeanDefinition beanDefinition) { Set checkedElements = new LinkedHashSet<>(this.injectedElements.size()); for (InjectedElement element : this.injectedElements) { @@ -96,9 +105,6 @@ public void checkConfigMembers(RootBeanDefinition beanDefinition) { if (!beanDefinition.isExternallyManagedConfigMember(member)) { beanDefinition.registerExternallyManagedConfigMember(member); checkedElements.add(element); - if (logger.isTraceEnabled()) { - logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element); - } } } this.checkedElements = checkedElements; @@ -110,9 +116,6 @@ public void inject(Object target, @Nullable String beanName, @Nullable PropertyV (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { - if (logger.isTraceEnabled()) { - logger.trace("Processing injected element of bean '" + beanName + "': " + element); - } element.inject(target, beanName, pvs); } } @@ -138,12 +141,12 @@ public void clear(@Nullable PropertyValues pvs) { * Return an {@code InjectionMetadata} instance, possibly for empty elements. * @param elements the elements to inject (possibly empty) * @param clazz the target class - * @return a new {@code InjectionMetadata} instance, - * or {@link #EMPTY} in case of no elements + * @return a new {@link #InjectionMetadata(Class, Collection)} instance * @since 5.2 */ public static InjectionMetadata forElements(Collection elements, Class clazz) { - return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements)); + return (elements.isEmpty() ? new InjectionMetadata(clazz, Collections.emptyList()) : + new InjectionMetadata(clazz, elements)); } /** @@ -151,9 +154,10 @@ public static InjectionMetadata forElements(Collection elements * @param metadata the existing metadata instance * @param clazz the current target class * @return {@code true} indicating a refresh, {@code false} otherwise + * @see #needsRefresh(Class) */ public static boolean needsRefresh(@Nullable InjectionMetadata metadata, Class clazz) { - return (metadata == null || metadata.targetClass != clazz); + return (metadata == null || metadata.needsRefresh(clazz)); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Lookup.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Lookup.java index 495354aa20c6..0fca4f3316a0 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Lookup.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Lookup.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,12 +41,11 @@ * regular constructors: i.e. lookup methods cannot get replaced on beans returned * from factory methods where we cannot dynamically provide a subclass for them. * - *

Concrete limitations in typical Spring configuration scenarios: - * When used with component scanning or any other mechanism that filters out abstract - * beans, provide stub implementations of your lookup methods to be able to declare - * them as concrete classes. And please remember that lookup methods won't work on - * beans returned from {@code @Bean} methods in configuration classes; you'll have - * to resort to {@code @Inject Provider} or the like instead. + *

Recommendations for typical Spring configuration scenarios: + * When a concrete class may be needed in certain scenarios, consider providing stub + * implementations of your lookup methods. And please remember that lookup methods + * won't work on beans returned from {@code @Bean} methods in configuration classes; + * you'll have to resort to {@code @Inject Provider} or the like instead. * * @author Juergen Hoeller * @since 4.1 diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Value.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Value.java index 36b1139e4cbc..bfa27305a6a1 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Value.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Value.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,14 +23,17 @@ import java.lang.annotation.Target; /** - * Annotation at the field or method/constructor parameter level - * that indicates a default value expression for the affected argument. + * Annotation used at the field or method/constructor parameter level + * that indicates a default value expression for the annotated element. * - *

Typically used for expression-driven dependency injection. Also supported - * for dynamic resolution of handler method parameters, e.g. in Spring MVC. + *

Typically used for expression-driven or property-driven dependency injection. + * Also supported for dynamic resolution of handler method arguments — for + * example, in Spring MVC. * - *

A common use case is to assign default field values using - * #{systemProperties.myProp} style expressions. + *

A common use case is to inject values using + * #{systemProperties.myProp} style SpEL (Spring Expression Language) + * expressions. Alternatively, values may be injected using + * ${my.app.myProp} style property placeholders. * *

Note that actual processing of the {@code @Value} annotation is performed * by a {@link org.springframework.beans.factory.config.BeanPostProcessor @@ -55,7 +58,8 @@ public @interface Value { /** - * The actual value expression — for example, #{systemProperties.myProp}. + * The actual value expression such as #{systemProperties.myProp} + * or property placeholder such as ${my.app.myProp}. */ String value(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinition.java index f22b60821288..5be39a0eaa11 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,16 +41,18 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { /** - * Scope identifier for the standard singleton scope: "singleton". + * Scope identifier for the standard singleton scope: {@value}. *

Note that extended bean factories might support further scopes. * @see #setScope + * @see ConfigurableBeanFactory#SCOPE_SINGLETON */ String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; /** - * Scope identifier for the standard prototype scope: "prototype". + * Scope identifier for the standard prototype scope: {@value}. *

Note that extended bean factories might support further scopes. * @see #setScope + * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE */ String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; @@ -236,7 +238,7 @@ default boolean hasConstructorArgumentValues() { MutablePropertyValues getPropertyValues(); /** - * Return if there are property values values defined for this bean. + * Return if there are property values defined for this bean. * @since 5.0.2 */ default boolean hasPropertyValues() { @@ -271,7 +273,7 @@ default boolean hasPropertyValues() { /** * Set the role hint for this {@code BeanDefinition}. The role hint - * provides the frameworks as well as tools with an indication of + * provides the frameworks as well as tools an indication of * the role and importance of a particular {@code BeanDefinition}. * @since 5.1 * @see #ROLE_APPLICATION @@ -282,7 +284,7 @@ default boolean hasPropertyValues() { /** * Get the role hint for this {@code BeanDefinition}. The role hint - * provides the frameworks as well as tools with an indication of + * provides the frameworks as well as tools an indication of * the role and importance of a particular {@code BeanDefinition}. * @see #ROLE_APPLICATION * @see #ROLE_SUPPORT @@ -345,7 +347,7 @@ default boolean hasPropertyValues() { /** * Return the originating BeanDefinition, or {@code null} if none. - * Allows for retrieving the decorated bean definition, if any. + *

Allows for retrieving the decorated bean definition, if any. *

Note that this method returns the immediate originator. Iterate through the * originator chain to find the original BeanDefinition as defined by the user. */ diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java index 98aa3a87ccfd..166fec179239 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,15 +51,15 @@ public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry { /** - * Scope identifier for the standard singleton scope: "singleton". - * Custom scopes can be added via {@code registerScope}. + * Scope identifier for the standard singleton scope: {@value}. + *

Custom scopes can be added via {@code registerScope}. * @see #registerScope */ String SCOPE_SINGLETON = "singleton"; /** - * Scope identifier for the standard prototype scope: "prototype". - * Custom scopes can be added via {@code registerScope}. + * Scope identifier for the standard prototype scope: {@value}. + *

Custom scopes can be added via {@code registerScope}. * @see #registerScope */ String SCOPE_PROTOTYPE = "prototype"; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java index 45da25fa84d0..c4d779e697b8 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -164,10 +164,10 @@ public ValueHolder getIndexedArgumentValue(int index, @Nullable Class require Assert.isTrue(index >= 0, "Index must not be negative"); ValueHolder valueHolder = this.indexedArgumentValues.get(index); if (valueHolder != null && - (valueHolder.getType() == null || - (requiredType != null && ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) && - (valueHolder.getName() == null || "".equals(requiredName) || - (requiredName != null && requiredName.equals(valueHolder.getName())))) { + (valueHolder.getType() == null || (requiredType != null && + ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) && + (valueHolder.getName() == null || (requiredName != null && + (requiredName.isEmpty() || requiredName.equals(valueHolder.getName()))))) { return valueHolder; } return null; @@ -277,17 +277,19 @@ public ValueHolder getGenericArgumentValue(Class requiredType, String require * @return the ValueHolder for the argument, or {@code null} if none found */ @Nullable - public ValueHolder getGenericArgumentValue(@Nullable Class requiredType, @Nullable String requiredName, @Nullable Set usedValueHolders) { + public ValueHolder getGenericArgumentValue(@Nullable Class requiredType, @Nullable String requiredName, + @Nullable Set usedValueHolders) { + for (ValueHolder valueHolder : this.genericArgumentValues) { if (usedValueHolders != null && usedValueHolders.contains(valueHolder)) { continue; } - if (valueHolder.getName() != null && !"".equals(requiredName) && - (requiredName == null || !valueHolder.getName().equals(requiredName))) { + if (valueHolder.getName() != null && (requiredName == null || + (!requiredName.isEmpty() && !requiredName.equals(valueHolder.getName())))) { continue; } - if (valueHolder.getType() != null && - (requiredType == null || !ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) { + if (valueHolder.getType() != null && (requiredType == null || + !ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) { continue; } if (requiredType != null && valueHolder.getType() == null && valueHolder.getName() == null && @@ -349,7 +351,9 @@ public ValueHolder getArgumentValue(int index, Class requiredType, String req * @return the ValueHolder for the argument, or {@code null} if none set */ @Nullable - public ValueHolder getArgumentValue(int index, @Nullable Class requiredType, @Nullable String requiredName, @Nullable Set usedValueHolders) { + public ValueHolder getArgumentValue(int index, @Nullable Class requiredType, + @Nullable String requiredName, @Nullable Set usedValueHolders) { + Assert.isTrue(index >= 0, "Index must not be negative"); ValueHolder valueHolder = getIndexedArgumentValue(index, requiredType, requiredName); if (valueHolder == null) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java index d63a3ddfc044..d5fd082162b6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -371,7 +371,7 @@ public void initParameterNameDiscovery(@Nullable ParameterNameDiscoverer paramet /** * Determine the name of the wrapped parameter/field. - * @return the declared name (never {@code null}) + * @return the declared name (may be {@code null} if unresolvable) */ @Nullable public String getDependencyName() { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java index fc29a9eda995..9a11f7af3ff2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,15 +36,16 @@ * Example XML bean definition: * *

- * <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
- *   <property name="driverClassName" value="${driver}"/>
- *   <property name="url" value="jdbc:${dbname}"/>
+ * <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ *   <property name="driverClassName" value="${driver}" />
+ *   <property name="url" value="jdbc:${dbname}" />
  * </bean>
  * 
* * Example properties file: * - *
driver=com.mysql.jdbc.Driver
+ * 
+ * driver=com.mysql.jdbc.Driver
  * dbname=mysql:mydb
* * Annotated bean definitions may take advantage of property replacement using @@ -56,7 +57,8 @@ * in bean references. Furthermore, placeholder values can also cross-reference * other placeholders, like: * - *
rootPath=myrootdir
+ * 
+ * rootPath=myrootdir
  * subPath=${rootPath}/subdir
* * In contrast to {@link PropertyOverrideConfigurer}, subclasses of this type allow @@ -71,13 +73,13 @@ * *

Default property values can be defined globally for each configurer instance * via the {@link #setProperties properties} property, or on a property-by-property basis - * using the default value separator which is {@code ":"} by default and - * customizable via {@link #setValueSeparator(String)}. + * using the value separator which is {@code ":"} by default and customizable via + * {@link #setValueSeparator(String)}. * *

Example XML property with default value: * *

- *   
+ *   <property name="url" value="jdbc:${dbname:defaultdb}" />
  * 
* * @author Chris Beams diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlProcessor.java index 340dee2dcac6..6d929f2ba5db 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,17 +25,23 @@ import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.reader.UnicodeReader; +import org.yaml.snakeyaml.representer.Representer; import org.springframework.core.CollectionFactory; import org.springframework.core.io.Resource; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -45,6 +51,7 @@ * * @author Dave Syer * @author Juergen Hoeller + * @author Sam Brannen * @since 4.1 */ public abstract class YamlProcessor { @@ -59,6 +66,8 @@ public abstract class YamlProcessor { private boolean matchDefault = true; + private Set supportedTypes = Collections.emptySet(); + /** * A map of document matchers allowing callers to selectively use only @@ -117,6 +126,27 @@ public void setResources(Resource... resources) { this.resources = resources; } + /** + * Set the supported types that can be loaded from YAML documents. + *

If no supported types are configured, all types encountered in YAML + * documents will be supported. If an unsupported type is encountered, an + * {@link IllegalStateException} will be thrown when the corresponding YAML + * node is processed. + * @param supportedTypes the supported types, or an empty array to clear the + * supported types + * @since 5.1.16 + * @see #createYaml() + */ + public void setSupportedTypes(Class... supportedTypes) { + if (ObjectUtils.isEmpty(supportedTypes)) { + this.supportedTypes = Collections.emptySet(); + } + else { + Assert.noNullElements(supportedTypes, "'supportedTypes' must not contain null elements"); + this.supportedTypes = Arrays.stream(supportedTypes).map(Class::getName) + .collect(Collectors.collectingAndThen(Collectors.toSet(), Collections::unmodifiableSet)); + } + } /** * Provide an opportunity for subclasses to process the Yaml parsed from the supplied @@ -142,12 +172,22 @@ protected void process(MatchCallback callback) { * Create the {@link Yaml} instance to use. *

The default implementation sets the "allowDuplicateKeys" flag to {@code false}, * enabling built-in duplicate key handling in SnakeYAML 1.18+. + *

As of Spring Framework 5.1.16, if custom {@linkplain #setSupportedTypes + * supported types} have been configured, the default implementation creates + * a {@code Yaml} instance that filters out unsupported types encountered in + * YAML documents. If an unsupported type is encountered, an + * {@link IllegalStateException} will be thrown when the node is processed. * @see LoaderOptions#setAllowDuplicateKeys(boolean) */ protected Yaml createYaml() { - LoaderOptions options = new LoaderOptions(); - options.setAllowDuplicateKeys(false); - return new Yaml(options); + LoaderOptions loaderOptions = new LoaderOptions(); + loaderOptions.setAllowDuplicateKeys(false); + + if (!this.supportedTypes.isEmpty()) { + return new Yaml(new FilteringConstructor(loaderOptions), new Representer(), + new DumperOptions(), loaderOptions); + } + return new Yaml(loaderOptions); } private boolean process(MatchCallback callback, Yaml yaml, Resource resource) { @@ -388,4 +428,24 @@ public enum ResolutionMethod { FIRST_FOUND } + + /** + * {@link Constructor} that supports filtering of unsupported types. + *

If an unsupported type is encountered in a YAML document, an + * {@link IllegalStateException} will be thrown from {@link #getClassForName}. + */ + private class FilteringConstructor extends Constructor { + + FilteringConstructor(LoaderOptions loaderOptions) { + super(loaderOptions); + } + + @Override + protected Class getClassForName(String name) throws ClassNotFoundException { + Assert.state(YamlProcessor.this.supportedTypes.contains(name), + () -> "Unsupported type encountered in YAML document: " + name); + return super.getClassForName(name); + } + } + } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java index c82964c23276..14427fee93ec 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -232,7 +232,6 @@ public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreExce * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ - @SuppressWarnings("rawtypes") public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { // Check for XML files and redirect them to the "standard" XmlBeanDefinitionReader String filename = encodedResource.getResource().getFilename(); @@ -245,10 +244,10 @@ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefin } @SuppressWarnings("serial") - Closure beans = new Closure(this) { + Closure beans = new Closure(this) { @Override public Object call(Object... args) { - invokeBeanDefiningClosure((Closure) args[0]); + invokeBeanDefiningClosure((Closure) args[0]); return null; } }; @@ -290,8 +289,7 @@ public void setVariable(String name, Object value) { * @param closure the block or closure * @return this {@code GroovyBeanDefinitionReader} instance */ - @SuppressWarnings("rawtypes") - public GroovyBeanDefinitionReader beans(Closure closure) { + public GroovyBeanDefinitionReader beans(Closure closure) { return invokeBeanDefiningClosure(closure); } @@ -312,29 +310,25 @@ public GenericBeanDefinition bean(Class type) { * @param args the constructors arguments and closure configurer * @return the bean definition */ - @SuppressWarnings("rawtypes") public AbstractBeanDefinition bean(Class type, Object...args) { GroovyBeanDefinitionWrapper current = this.currentBeanDefinition; try { - Closure callable = null; - Collection constructorArgs = null; + Closure callable = null; + Collection constructorArgs = null; if (!ObjectUtils.isEmpty(args)) { int index = args.length; Object lastArg = args[index - 1]; - if (lastArg instanceof Closure) { - callable = (Closure) lastArg; + if (lastArg instanceof Closure) { + callable = (Closure) lastArg; index--; } - if (index > -1) { - constructorArgs = resolveConstructorArguments(args, 0, index); - } + constructorArgs = resolveConstructorArguments(args, 0, index); } this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(null, type, constructorArgs); if (callable != null) { callable.call(this.currentBeanDefinition); } return this.currentBeanDefinition.getBeanDefinition(); - } finally { this.currentBeanDefinition = current; @@ -381,11 +375,10 @@ public void importBeans(String resourcePattern) throws IOException { * takes a class argument. */ @Override - @SuppressWarnings("rawtypes") public Object invokeMethod(String name, Object arg) { Object[] args = (Object[])arg; if ("beans".equals(name) && args.length == 1 && args[0] instanceof Closure) { - return beans((Closure) args[0]); + return beans((Closure) args[0]); } else if ("ref".equals(name)) { String refName; @@ -435,14 +428,13 @@ private boolean addDeferredProperty(String property, Object newValue) { return false; } - @SuppressWarnings("rawtypes") private void finalizeDeferredProperties() { for (DeferredProperty dp : this.deferredProperties.values()) { if (dp.value instanceof List) { - dp.value = manageListIfNecessary((List) dp.value); + dp.value = manageListIfNecessary((List) dp.value); } else if (dp.value instanceof Map) { - dp.value = manageMapIfNecessary((Map) dp.value); + dp.value = manageMapIfNecessary((Map) dp.value); } dp.apply(); } @@ -454,8 +446,7 @@ else if (dp.value instanceof Map) { * @param callable the closure argument * @return this {@code GroovyBeanDefinitionReader} instance */ - @SuppressWarnings("rawtypes") - protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) { + protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) { callable.setDelegate(this); callable.call(); finalizeDeferredProperties(); @@ -469,7 +460,6 @@ protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) * argument is sometimes a closure. All the arguments in between are constructor arguments. * @return the bean definition wrapper */ - @SuppressWarnings("rawtypes") private GroovyBeanDefinitionWrapper invokeBeanDefiningMethod(String beanName, Object[] args) { boolean hasClosureArgument = (args[args.length - 1] instanceof Closure); if (args[0] instanceof Class) { @@ -495,11 +485,12 @@ else if (args[0] instanceof RuntimeBeanReference) { else if (args[0] instanceof Map) { // named constructor arguments if (args.length > 1 && args[1] instanceof Class) { - List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length); + List constructorArgs = + resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length); this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class) args[1], constructorArgs); - Map namedArgs = (Map) args[0]; - for (Object o : namedArgs.keySet()) { - String propName = (String) o; + Map namedArgs = (Map) args[0]; + for (Object key : namedArgs.keySet()) { + String propName = (String) key; setProperty(propName, namedArgs.get(propName)); } } @@ -507,7 +498,7 @@ else if (args[0] instanceof Map) { else { this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName); // First arg is the map containing factoryBean : factoryMethod - Map.Entry factoryBeanEntry = (Map.Entry) ((Map) args[0]).entrySet().iterator().next(); + Map.Entry factoryBeanEntry = ((Map) args[0]).entrySet().iterator().next(); // If we have a closure body, that will be the last argument. // In between are the constructor args int constructorArgsTest = (hasClosureArgument ? 2 : 1); @@ -531,12 +522,13 @@ else if (args[0] instanceof Closure) { this.currentBeanDefinition.getBeanDefinition().setAbstract(true); } else { - List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length); + List constructorArgs = + resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length); this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null, constructorArgs); } if (hasClosureArgument) { - Closure callable = (Closure) args[args.length - 1]; + Closure callable = (Closure) args[args.length - 1]; callable.setDelegate(this); callable.setResolveStrategy(Closure.DELEGATE_FIRST); callable.call(this.currentBeanDefinition); @@ -549,7 +541,6 @@ else if (args[0] instanceof Closure) { return beanDefinition; } - @SuppressWarnings("rawtypes") protected List resolveConstructorArguments(Object[] args, int start, int end) { Object[] constructorArgs = Arrays.copyOfRange(args, start, end); for (int i = 0; i < constructorArgs.length; i++) { @@ -557,10 +548,10 @@ protected List resolveConstructorArguments(Object[] args, int start, int constructorArgs[i] = constructorArgs[i].toString(); } else if (constructorArgs[i] instanceof List) { - constructorArgs[i] = manageListIfNecessary((List) constructorArgs[i]); + constructorArgs[i] = manageListIfNecessary((List) constructorArgs[i]); } else if (constructorArgs[i] instanceof Map){ - constructorArgs[i] = manageMapIfNecessary((Map) constructorArgs[i]); + constructorArgs[i] = manageMapIfNecessary((Map) constructorArgs[i]); } } return Arrays.asList(constructorArgs); @@ -621,7 +612,6 @@ public void setProperty(String name, Object value) { } } - @SuppressWarnings("rawtypes") protected void applyPropertyToBeanDefinition(String name, Object value) { if (value instanceof GString) { value = value.toString(); @@ -632,7 +622,7 @@ protected void applyPropertyToBeanDefinition(String name, Object value) { else if (value instanceof Closure) { GroovyBeanDefinitionWrapper current = this.currentBeanDefinition; try { - Closure callable = (Closure) value; + Closure callable = (Closure) value; Class parameterType = callable.getParameterTypes()[0]; if (Object.class == parameterType) { this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(""); @@ -833,8 +823,8 @@ public boolean add(Object value) { return retVal; } - @SuppressWarnings({ "rawtypes", "unused" }) - public boolean addAll(Collection values) { + @SuppressWarnings("unused") + public boolean addAll(Collection values) { boolean retVal = (Boolean) InvokerHelper.invokeMethod(this.propertyValue, "addAll", values); for (Object value : values) { updateDeferredProperties(value); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionWrapper.java b/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionWrapper.java index 6e702036314a..d1aeff7d0bcc 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionWrapper.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -173,7 +173,6 @@ else if (dynamicProperties.contains(property)) { } @Override - @SuppressWarnings("rawtypes") public void setProperty(String property, Object newValue) { if (PARENT.equals(property)) { setParent(newValue); @@ -197,7 +196,7 @@ else if (Boolean.TRUE.equals(newValue)) { // constructorArgs else if (CONSTRUCTOR_ARGS.equals(property) && newValue instanceof List) { ConstructorArgumentValues cav = new ConstructorArgumentValues(); - List args = (List) newValue; + List args = (List) newValue; for (Object arg : args) { cav.addGenericArgumentValue(arg); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/BeanEntry.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/BeanEntry.java index 207650a27ba3..ccba6d76e688 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/BeanEntry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/BeanEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,11 +24,11 @@ */ public class BeanEntry implements ParseState.Entry { - private String beanDefinitionName; + private final String beanDefinitionName; /** - * Creates a new instance of {@link BeanEntry} class. + * Create a new {@code BeanEntry} instance. * @param beanDefinitionName the name of the associated bean definition */ public BeanEntry(String beanDefinitionName) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ParseState.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ParseState.java index 23a013ce91f1..0277bc0a0f9c 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ParseState.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ParseState.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,69 +16,63 @@ package org.springframework.beans.factory.parsing; -import java.util.LinkedList; +import java.util.ArrayDeque; import org.springframework.lang.Nullable; /** - * Simple {@link LinkedList}-based structure for tracking the logical position during - * a parsing process. {@link Entry entries} are added to the LinkedList at - * each point during the parse phase in a reader-specific manner. + * Simple {@link ArrayDeque}-based structure for tracking the logical position during + * a parsing process. {@link Entry entries} are added to the ArrayDeque at each point + * during the parse phase in a reader-specific manner. * *

Calling {@link #toString()} will render a tree-style view of the current logical - * position in the parse phase. This representation is intended for use in - * error messages. + * position in the parse phase. This representation is intended for use in error messages. * * @author Rob Harrop + * @author Juergen Hoeller * @since 2.0 */ public final class ParseState { /** - * Tab character used when rendering the tree-style representation. + * Internal {@link ArrayDeque} storage. */ - private static final char TAB = '\t'; - - /** - * Internal {@link LinkedList} storage. - */ - private final LinkedList state; + private final ArrayDeque state; /** - * Create a new {@code ParseState} with an empty {@link LinkedList}. + * Create a new {@code ParseState} with an empty {@link ArrayDeque}. */ public ParseState() { - this.state = new LinkedList<>(); + this.state = new ArrayDeque<>(); } /** - * Create a new {@code ParseState} whose {@link LinkedList} is a {@link Object#clone clone} - * of that of the passed in {@code ParseState}. + * Create a new {@code ParseState} whose {@link ArrayDeque} is a clone + * of the state in the passed-in {@code ParseState}. */ - @SuppressWarnings("unchecked") private ParseState(ParseState other) { - this.state = (LinkedList) other.state.clone(); + this.state = other.state.clone(); } /** - * Add a new {@link Entry} to the {@link LinkedList}. + * Add a new {@link Entry} to the {@link ArrayDeque}. */ public void push(Entry entry) { this.state.push(entry); } /** - * Remove an {@link Entry} from the {@link LinkedList}. + * Remove an {@link Entry} from the {@link ArrayDeque}. */ public void pop() { this.state.pop(); } /** - * Return the {@link Entry} currently at the top of the {@link LinkedList} or - * {@code null} if the {@link LinkedList} is empty. + * Return the {@link Entry} currently at the top of the {@link ArrayDeque} or + * {@code null} if the {@link ArrayDeque} is empty. */ @Nullable public Entry peek() { @@ -99,16 +93,18 @@ public ParseState snapshot() { */ @Override public String toString() { - StringBuilder sb = new StringBuilder(); - for (int x = 0; x < this.state.size(); x++) { - if (x > 0) { + StringBuilder sb = new StringBuilder(64); + int i = 0; + for (ParseState.Entry entry : this.state) { + if (i > 0) { sb.append('\n'); - for (int y = 0; y < x; y++) { - sb.append(TAB); + for (int j = 0; j < i; j++) { + sb.append('\t'); } sb.append("-> "); } - sb.append(this.state.get(x)); + sb.append(entry); + i++; } return sb.toString(); } @@ -118,7 +114,6 @@ public String toString() { * Marker interface for entries into the {@link ParseState}. */ public interface Entry { - } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/PropertyEntry.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/PropertyEntry.java index 983e72101b87..c20235a09b78 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/PropertyEntry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/PropertyEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,14 +30,12 @@ public class PropertyEntry implements ParseState.Entry { /** - * Creates a new instance of the {@link PropertyEntry} class. + * Create a new {@code PropertyEntry} instance. * @param name the name of the JavaBean property represented by this instance - * @throws IllegalArgumentException if the supplied {@code name} is {@code null} - * or consists wholly of whitespace */ public PropertyEntry(String name) { if (!StringUtils.hasText(name)) { - throw new IllegalArgumentException("Invalid property name '" + name + "'."); + throw new IllegalArgumentException("Invalid property name '" + name + "'"); } this.name = name; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/QualifierEntry.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/QualifierEntry.java index 8fc3207e80ec..45283e5838ce 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/QualifierEntry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/QualifierEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,16 +26,21 @@ */ public class QualifierEntry implements ParseState.Entry { - private String typeName; + private final String typeName; + /** + * Create a new {@code QualifierEntry} instance. + * @param typeName the name of the qualifier type + */ public QualifierEntry(String typeName) { if (!StringUtils.hasText(typeName)) { - throw new IllegalArgumentException("Invalid qualifier type '" + typeName + "'."); + throw new IllegalArgumentException("Invalid qualifier type '" + typeName + "'"); } this.typeName = typeName; } + @Override public String toString() { return "Qualifier '" + this.typeName + "'"; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ReaderContext.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ReaderContext.java index 7c31fe994b7d..2b95aa8f6c3b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ReaderContext.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ReaderContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -152,14 +152,14 @@ public void warning(String message, @Nullable Object source, @Nullable ParseStat // Explicit parse events /** - * Fire an defaults-registered event. + * Fire a defaults-registered event. */ public void fireDefaultsRegistered(DefaultsDefinition defaultsDefinition) { this.eventListener.defaultsRegistered(defaultsDefinition); } /** - * Fire an component-registered event. + * Fire a component-registered event. */ public void fireComponentRegistered(ComponentDefinition componentDefinition) { this.eventListener.componentRegistered(componentDefinition); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 35d0df235c27..d8447022b144 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -311,7 +311,7 @@ public T createBean(Class beanClass) throws BeansException { public void autowireBean(Object existingBean) { // Use non-singleton bean definition, to avoid registering bean as dependent bean. RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean)); - bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(SCOPE_PROTOTYPE); bd.allowCaching = ClassUtils.isCacheSafe(bd.getBeanClass(), getBeanClassLoader()); BeanWrapper bw = new BeanWrapperImpl(existingBean); initBeanWrapper(bw); @@ -331,7 +331,7 @@ public Object configureBean(Object existingBean, String beanName) throws BeansEx bd = new RootBeanDefinition(mbd); } if (!bd.isPrototype()) { - bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(SCOPE_PROTOTYPE); bd.allowCaching = ClassUtils.isCacheSafe(ClassUtils.getUserClass(existingBean), getBeanClassLoader()); } BeanWrapper bw = new BeanWrapperImpl(existingBean); @@ -349,28 +349,27 @@ public Object configureBean(Object existingBean, String beanName) throws BeansEx public Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException { // Use non-singleton bean definition, to avoid registering bean as dependent bean. RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck); - bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(SCOPE_PROTOTYPE); return createBean(beanClass.getName(), bd, null); } @Override public Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException { // Use non-singleton bean definition, to avoid registering bean as dependent bean. - final RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck); - bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck); + bd.setScope(SCOPE_PROTOTYPE); if (bd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) { return autowireConstructor(beanClass.getName(), bd, null, null).getWrappedInstance(); } else { Object bean; - final BeanFactory parent = this; if (System.getSecurityManager() != null) { - bean = AccessController.doPrivileged((PrivilegedAction) () -> - getInstantiationStrategy().instantiate(bd, null, parent), + bean = AccessController.doPrivileged( + (PrivilegedAction) () -> getInstantiationStrategy().instantiate(bd, null, this), getAccessControlContext()); } else { - bean = getInstantiationStrategy().instantiate(bd, null, parent); + bean = getInstantiationStrategy().instantiate(bd, null, this); } populateBean(beanClass.getName(), bd, new BeanWrapperImpl(bean)); return bean; @@ -387,7 +386,7 @@ public void autowireBeanProperties(Object existingBean, int autowireMode, boolea // Use non-singleton bean definition, to avoid registering bean as dependent bean. RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean), autowireMode, dependencyCheck); - bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(SCOPE_PROTOTYPE); BeanWrapper bw = new BeanWrapperImpl(existingBean); initBeanWrapper(bw); populateBean(bd.getBeanClass().getName(), bd, bw); @@ -545,7 +544,7 @@ protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable O * @see #instantiateUsingFactoryMethod * @see #autowireConstructor */ - protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) + protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. @@ -556,7 +555,7 @@ protected Object doCreateBean(final String beanName, final RootBeanDefinition mb if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } - final Object bean = instanceWrapper.getWrappedInstance(); + Object bean = instanceWrapper.getWrappedInstance(); Class beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; @@ -625,7 +624,7 @@ else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + - "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); + "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); } } } @@ -1014,6 +1013,11 @@ private FactoryBean getSingletonFactoryBeanForTypeCheck(String beanName, Root throw ex; } catch (BeanCreationException ex) { + // Don't swallow a linkage error since it contains a full stacktrace on + // first occurrence... and just a plain NoClassDefFoundError afterwards. + if (ex.contains(LinkageError.class)) { + throw ex; + } // Instantiation failure, maybe too early... if (logger.isDebugEnabled()) { logger.debug("Bean creation exception on singleton FactoryBean type check: " + ex); @@ -1299,17 +1303,16 @@ protected Constructor[] determineConstructorsFromBeanPostProcessors(@Nullable * @param mbd the bean definition for the bean * @return a BeanWrapper for the new instance */ - protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { + protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) { try { Object beanInstance; - final BeanFactory parent = this; if (System.getSecurityManager() != null) { - beanInstance = AccessController.doPrivileged((PrivilegedAction) () -> - getInstantiationStrategy().instantiate(mbd, beanName, parent), + beanInstance = AccessController.doPrivileged( + (PrivilegedAction) () -> getInstantiationStrategy().instantiate(mbd, beanName, this), getAccessControlContext()); } else { - beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); + beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); } BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); @@ -1381,24 +1384,17 @@ protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable B // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the // state of the bean before properties are set. This can be used, for example, // to support styles of field injection. - boolean continueWithPropertyPopulation = true; - if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { - continueWithPropertyPopulation = false; - break; + return; } } } } - if (!continueWithPropertyPopulation) { - return; - } - PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); int resolvedAutowireMode = mbd.getResolvedAutowireMode(); @@ -1513,7 +1509,7 @@ protected void autowireByType( if (Object.class != pd.getPropertyType()) { MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); // Do not allow eager init for type matching in case of a prioritized post-processor. - boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance()); + boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered); DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter); if (autowiredArgument != null) { @@ -1779,7 +1775,7 @@ private Object convertForProperty( * @see #invokeInitMethods * @see #applyBeanPostProcessorsAfterInitialization */ - protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { + protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction) () -> { invokeAwareMethods(beanName, bean); @@ -1810,7 +1806,7 @@ protected Object initializeBean(final String beanName, final Object bean, @Nulla return wrappedBean; } - private void invokeAwareMethods(final String beanName, final Object bean) { + private void invokeAwareMethods(String beanName, Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); @@ -1839,7 +1835,7 @@ private void invokeAwareMethods(final String beanName, final Object bean) { * @throws Throwable if thrown by init methods or by the invocation process * @see #invokeCustomInitMethod */ - protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) + protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); @@ -1880,7 +1876,7 @@ protected void invokeInitMethods(String beanName, final Object bean, @Nullable R * methods with arguments. * @see #invokeInitMethods */ - protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) + protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd) throws Throwable { String initMethodName = mbd.getInitMethodName(); @@ -1915,8 +1911,8 @@ protected void invokeCustomInitMethod(String beanName, final Object bean, RootBe return null; }); try { - AccessController.doPrivileged((PrivilegedExceptionAction) () -> - methodToInvoke.invoke(bean), getAccessControlContext()); + AccessController.doPrivileged((PrivilegedExceptionAction) + () -> methodToInvoke.invoke(bean), getAccessControlContext()); } catch (PrivilegedActionException pae) { InvocationTargetException ex = (InvocationTargetException) pae.getException(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java index b1c6691d0968..d4b0aef01522 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -403,16 +403,29 @@ public String getBeanClassName() { /** * Specify the class for this bean. + * @see #setBeanClassName(String) */ public void setBeanClass(@Nullable Class beanClass) { this.beanClass = beanClass; } /** - * Return the class of the wrapped bean (assuming it is resolved already). - * @return the bean class (never {@code null}) + * Return the specified class of the bean definition (assuming it is resolved already). + *

NOTE: This is an initial class reference as declared in the bean metadata + * definition, potentially combined with a declared factory method or a + * {@link org.springframework.beans.factory.FactoryBean} which may lead to a different + * runtime type of the bean, or not being set at all in case of an instance-level + * factory method (which is resolved via {@link #getFactoryBeanName()} instead). + * Do not use this for runtime type introspection of arbitrary bean definitions. + * The recommended way to find out about the actual runtime type of a particular bean + * is a {@link org.springframework.beans.factory.BeanFactory#getType} call for the + * specified bean name; this takes all of the above cases into account and returns the + * type of object that a {@link org.springframework.beans.factory.BeanFactory#getBean} + * call is going to return for the same bean name. + * @return the resolved bean class (never {@code null}) * @throws IllegalStateException if the bean definition does not define a bean class, * or a specified bean class name has not been resolved into an actual Class yet + * @see #getBeanClassName() * @see #hasBeanClass() * @see #setBeanClass(Class) * @see #resolveBeanClass(ClassLoader) @@ -932,16 +945,20 @@ public String getInitMethodName() { } /** - * Specify whether or not the configured init method is the default. - *

The default value is {@code false}. + * Specify whether or not the configured initializer method is the default. + *

The default value is {@code true} for a locally specified init method + * but switched to {@code false} for a shared setting in a defaults section + * (e.g. {@code bean init-method} versus {@code beans default-init-method} + * level in XML) which might not apply to all contained bean definitions. * @see #setInitMethodName + * @see #applyDefaults */ public void setEnforceInitMethod(boolean enforceInitMethod) { this.enforceInitMethod = enforceInitMethod; } /** - * Indicate whether the configured init method is the default. + * Indicate whether the configured initializer method is the default. * @see #getInitMethodName() */ public boolean isEnforceInitMethod() { @@ -968,8 +985,12 @@ public String getDestroyMethodName() { /** * Specify whether or not the configured destroy method is the default. - *

The default value is {@code false}. + *

The default value is {@code true} for a locally specified destroy method + * but switched to {@code false} for a shared setting in a defaults section + * (e.g. {@code bean destroy-method} versus {@code beans default-destroy-method} + * level in XML) which might not apply to all contained bean definitions. * @see #setDestroyMethodName + * @see #applyDefaults */ public void setEnforceDestroyMethod(boolean enforceDestroyMethod) { this.enforceDestroyMethod = enforceDestroyMethod; @@ -977,7 +998,7 @@ public void setEnforceDestroyMethod(boolean enforceDestroyMethod) { /** * Indicate whether the configured destroy method is the default. - * @see #getDestroyMethodName + * @see #getDestroyMethodName() */ public boolean isEnforceDestroyMethod() { return this.enforceDestroyMethod; @@ -1161,38 +1182,56 @@ public boolean equals(@Nullable Object other) { return false; } AbstractBeanDefinition that = (AbstractBeanDefinition) other; - boolean rtn = ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName()); - rtn = rtn &= ObjectUtils.nullSafeEquals(this.scope, that.scope); - rtn = rtn &= this.abstractFlag == that.abstractFlag; - rtn = rtn &= this.lazyInit == that.lazyInit; - rtn = rtn &= this.autowireMode == that.autowireMode; - rtn = rtn &= this.dependencyCheck == that.dependencyCheck; - rtn = rtn &= Arrays.equals(this.dependsOn, that.dependsOn); - rtn = rtn &= this.autowireCandidate == that.autowireCandidate; - rtn = rtn &= ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers); - rtn = rtn &= this.primary == that.primary; - rtn = rtn &= this.nonPublicAccessAllowed == that.nonPublicAccessAllowed; - rtn = rtn &= this.lenientConstructorResolution == that.lenientConstructorResolution; - rtn = rtn &= ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues); - rtn = rtn &= ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues); - rtn = rtn &= ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides); - rtn = rtn &= ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName); - rtn = rtn &= ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName); - rtn = rtn &= ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName); - rtn = rtn &= this.enforceInitMethod == that.enforceInitMethod; - rtn = rtn &= ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName); - rtn = rtn &= this.enforceDestroyMethod == that.enforceDestroyMethod; - rtn = rtn &= this.synthetic == that.synthetic; - rtn = rtn &= this.role == that.role; - return rtn && super.equals(other); + return (ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName()) && + ObjectUtils.nullSafeEquals(this.scope, that.scope) && + this.abstractFlag == that.abstractFlag && + this.lazyInit == that.lazyInit && + this.autowireMode == that.autowireMode && + this.dependencyCheck == that.dependencyCheck && + Arrays.equals(this.dependsOn, that.dependsOn) && + this.autowireCandidate == that.autowireCandidate && + ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers) && + this.primary == that.primary && + this.nonPublicAccessAllowed == that.nonPublicAccessAllowed && + this.lenientConstructorResolution == that.lenientConstructorResolution && + equalsConstructorArgumentValues(that) && + equalsPropertyValues(that) && + ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides) && + ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName) && + ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName) && + ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName) && + this.enforceInitMethod == that.enforceInitMethod && + ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName) && + this.enforceDestroyMethod == that.enforceDestroyMethod && + this.synthetic == that.synthetic && + this.role == that.role && + super.equals(other)); + } + + private boolean equalsConstructorArgumentValues(AbstractBeanDefinition other) { + if (!hasConstructorArgumentValues()) { + return !other.hasConstructorArgumentValues(); + } + return ObjectUtils.nullSafeEquals(this.constructorArgumentValues, other.constructorArgumentValues); + } + + private boolean equalsPropertyValues(AbstractBeanDefinition other) { + if (!hasPropertyValues()) { + return !other.hasPropertyValues(); + } + return ObjectUtils.nullSafeEquals(this.propertyValues, other.propertyValues); } @Override public int hashCode() { int hashCode = ObjectUtils.nullSafeHashCode(getBeanClassName()); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.scope); - hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues); - hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues); + if (hasConstructorArgumentValues()) { + hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues); + } + if (hasPropertyValues()) { + hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues); + } hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryBeanName); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryMethodName); hashCode = 29 * hashCode + super.hashCode(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 29fe3a8c4649..ec5356e6a79a 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -150,7 +150,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp /** String resolvers to apply e.g. to annotation attribute values. */ private final List embeddedValueResolvers = new CopyOnWriteArrayList<>(); - /** BeanPostProcessors to apply in createBean. */ + /** BeanPostProcessors to apply. */ private final List beanPostProcessors = new CopyOnWriteArrayList<>(); /** Indicates whether any InstantiationAwareBeanPostProcessors have been registered. */ @@ -239,10 +239,11 @@ public T getBean(String name, @Nullable Class requiredType, @Nullable Obj * @throws BeansException if the bean could not be created */ @SuppressWarnings("unchecked") - protected T doGetBean(final String name, @Nullable final Class requiredType, - @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { + protected T doGetBean( + String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) + throws BeansException { - final String beanName = transformedBeanName(name); + String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. @@ -294,7 +295,7 @@ else if (requiredType != null) { } try { - final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); + RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. @@ -348,7 +349,10 @@ else if (mbd.isPrototype()) { else { String scopeName = mbd.getScope(); - final Scope scope = this.scopes.get(scopeName); + if (!StringUtils.hasLength(scopeName)) { + throw new IllegalStateException("No scope name defined for bean '" + beanName + "'"); + } + Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } @@ -472,10 +476,12 @@ public boolean isPrototype(String name) throws NoSuchBeanDefinitionException { return false; } if (isFactoryBean(beanName, mbd)) { - final FactoryBean fb = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); + FactoryBean fb = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); if (System.getSecurityManager() != null) { - return AccessController.doPrivileged((PrivilegedAction) () -> - ((fb instanceof SmartFactoryBean && ((SmartFactoryBean) fb).isPrototype()) || !fb.isSingleton()), + return AccessController.doPrivileged( + (PrivilegedAction) () -> + ((fb instanceof SmartFactoryBean && ((SmartFactoryBean) fb).isPrototype()) || + !fb.isSingleton()), getAccessControlContext()); } else { @@ -725,8 +731,9 @@ public String[] getAliases(String name) { aliases.add(fullBeanName); } String[] retrievedAliases = super.getAliases(beanName); + String prefix = factoryPrefix ? FACTORY_BEAN_PREFIX : ""; for (String retrievedAlias : retrievedAliases) { - String alias = (factoryPrefix ? FACTORY_BEAN_PREFIX : "") + retrievedAlias; + String alias = prefix + retrievedAlias; if (!alias.equals(name)) { aliases.add(alias); } @@ -768,6 +775,9 @@ public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) { if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) { throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory); } + if (this == parentBeanFactory) { + throw new IllegalStateException("Cannot set parent bean factory to self"); + } this.parentBeanFactory = parentBeanFactory; } @@ -944,7 +954,7 @@ public List getBeanPostProcessors() { /** * Return whether this factory holds a InstantiationAwareBeanPostProcessor - * that will get applied to singleton beans on shutdown. + * that will get applied to singleton beans on creation. * @see #addBeanPostProcessor * @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor */ @@ -1317,7 +1327,6 @@ protected RootBeanDefinition getMergedBeanDefinition( if (mbd == null || mbd.stale) { previous = mbd; - mbd = null; if (bd.getParentName() == null) { // Use copy of given root bean definition. if (bd instanceof RootBeanDefinition) { @@ -1343,7 +1352,7 @@ protected RootBeanDefinition getMergedBeanDefinition( else { throw new NoSuchBeanDefinitionException(parentBeanName, "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName + - "': cannot be resolved without an AbstractBeanFactory parent"); + "': cannot be resolved without a ConfigurableBeanFactory parent"); } } } @@ -1358,7 +1367,7 @@ protected RootBeanDefinition getMergedBeanDefinition( // Set default singleton scope, if not configured before. if (!StringUtils.hasLength(mbd.getScope())) { - mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON); + mbd.setScope(SCOPE_SINGLETON); } // A bean contained in a non-singleton bean cannot be a singleton itself. @@ -1454,7 +1463,7 @@ public void clearMetadataCache() { * @throws CannotLoadBeanClassException if we failed to load the class */ @Nullable - protected Class resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class... typesToMatch) + protected Class resolveBeanClass(RootBeanDefinition mbd, String beanName, Class... typesToMatch) throws CannotLoadBeanClassException { try { @@ -1462,8 +1471,8 @@ protected Class resolveBeanClass(final RootBeanDefinition mbd, String beanNam return mbd.getBeanClass(); } if (System.getSecurityManager() != null) { - return AccessController.doPrivileged((PrivilegedExceptionAction>) () -> - doResolveBeanClass(mbd, typesToMatch), getAccessControlContext()); + return AccessController.doPrivileged((PrivilegedExceptionAction>) + () -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext()); } else { return doResolveBeanClass(mbd, typesToMatch); @@ -1612,21 +1621,22 @@ protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) { /** * Determine the bean type for the given FactoryBean definition, as far as possible. * Only called if there is no singleton instance registered for the target bean - * already. Implementations are only allowed to instantiate the factory bean if - * {@code allowInit} is {@code true}, otherwise they should try to determine the - * result through other means. + * already. The implementation is allowed to instantiate the target factory bean if + * {@code allowInit} is {@code true} and the type cannot be determined another way; + * otherwise it is restricted to introspecting signatures and related metadata. *

If no {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} if set on the bean definition * and {@code allowInit} is {@code true}, the default implementation will create * the FactoryBean via {@code getBean} to call its {@code getObjectType} method. * Subclasses are encouraged to optimize this, typically by inspecting the generic - * signature of the factory bean class or the factory method that creates it. If - * subclasses do instantiate the FactoryBean, they should consider trying the - * {@code getObjectType} method without fully populating the bean. If this fails, a - * full FactoryBean creation as performed by this implementation should be used as - * fallback. + * signature of the factory bean class or the factory method that creates it. + * If subclasses do instantiate the FactoryBean, they should consider trying the + * {@code getObjectType} method without fully populating the bean. If this fails, + * a full FactoryBean creation as performed by this implementation should be used + * as fallback. * @param beanName the name of the bean * @param mbd the merged bean definition for the bean - * @param allowInit if initialization of the FactoryBean is permitted + * @param allowInit if initialization of the FactoryBean is permitted if the type + * cannot be determined another way * @return the type for the bean if determinable, otherwise {@code ResolvableType.NONE} * @since 5.2 * @see org.springframework.beans.factory.FactoryBean#getObjectType() @@ -1642,7 +1652,7 @@ protected ResolvableType getTypeForFactoryBean(String beanName, RootBeanDefiniti try { FactoryBean factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true); Class objectType = getTypeForFactoryBean(factoryBean); - return (objectType != null) ? ResolvableType.forClass(objectType) : ResolvableType.NONE; + return (objectType != null ? ResolvableType.forClass(objectType) : ResolvableType.NONE); } catch (BeanCreationException ex) { if (ex.contains(BeanCurrentlyInCreationException.class)) { @@ -1652,7 +1662,7 @@ else if (mbd.isLazyInit()) { logger.trace(LogMessage.format("Bean creation exception on lazy FactoryBean type check: %s", ex)); } else { - logger.debug(LogMessage.format("Bean creation exception on non-lazy FactoryBean type check: %s", ex)); + logger.debug(LogMessage.format("Bean creation exception on eager FactoryBean type check: %s", ex)); } onSuppressedException(ex); } @@ -1771,7 +1781,7 @@ protected boolean hasBeanCreationStarted() { * Get the object for the given bean instance, either the bean * instance itself or its created object in case of a FactoryBean. * @param beanInstance the shared bean instance - * @param name name that may include factory dereference prefix + * @param name the name that may include factory dereference prefix * @param beanName the canonical bean name * @param mbd the merged bean definition * @return the object to expose for the bean diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java index bb1740e3972d..0a1f0a7d6910 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.beans.factory.support; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.lang.Nullable; @@ -99,4 +100,22 @@ default Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor return null; } + /** + * Return a clone of this resolver instance if necessary, retaining its local + * configuration and allowing for the cloned instance to get associated with + * a new bean factory, or this original instance if there is no such state. + *

The default implementation creates a separate instance via the default + * class constructor, assuming no specific configuration state to copy. + * Subclasses may override this with custom configuration state handling + * or with standard {@link Cloneable} support (as implemented by Spring's + * own configurable {@code AutowireCandidateResolver} variants), or simply + * return {@code this} (as in {@link SimpleAutowireCandidateResolver}). + * @since 5.2.7 + * @see GenericTypeAwareAutowireCandidateResolver#cloneIfNecessary() + * @see DefaultListableBeanFactory#copyConfigurationFrom + */ + default AutowireCandidateResolver cloneIfNecessary() { + return BeanUtils.instantiateClass(getClass()); + } + } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java index 67f952567573..cb569b07d626 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java @@ -51,7 +51,7 @@ */ abstract class AutowireUtils { - private static final Comparator EXECUTABLE_COMPARATOR = (e1, e2) -> { + public static final Comparator EXECUTABLE_COMPARATOR = (e1, e2) -> { int result = Boolean.compare(Modifier.isPublic(e2.getModifiers()), Modifier.isPublic(e1.getModifiers())); return result != 0 ? result : Integer.compare(e2.getParameterCount(), e1.getParameterCount()); }; @@ -97,7 +97,7 @@ public static boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) { // It was declared by CGLIB, but we might still want to autowire it // if it was actually declared by the superclass. Class superclass = wm.getDeclaringClass().getSuperclass(); - return !ClassUtils.hasMethod(superclass, wm.getName(), wm.getParameterTypes()); + return !ClassUtils.hasMethod(superclass, wm); } /** @@ -112,8 +112,7 @@ public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set targetClass = setter.getDeclaringClass(); for (Class ifc : interfaces) { - if (ifc.isAssignableFrom(targetClass) && - ClassUtils.hasMethod(ifc, setter.getName(), setter.getParameterTypes())) { + if (ifc.isAssignableFrom(targetClass) && ClassUtils.hasMethod(ifc, setter)) { return true; } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java index f98567a07070..5da53bfe3b67 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ * @author Mark Fisher * @author Juergen Hoeller * @since 2.5 + * @see AbstractBeanDefinition#applyDefaults */ public class BeanDefinitionDefaults { @@ -46,6 +47,7 @@ public class BeanDefinitionDefaults { * Set whether beans should be lazily initialized by default. *

If {@code false}, the bean will get instantiated on startup by bean * factories that perform eager initialization of singletons. + * @see AbstractBeanDefinition#setLazyInit */ public void setLazyInit(boolean lazyInit) { this.lazyInit = lazyInit; @@ -78,6 +80,7 @@ public Boolean getLazyInit() { * (however, there may still be explicit annotation-driven autowiring). * @param autowireMode the autowire mode to set. * Must be one of the constants defined in {@link AbstractBeanDefinition}. + * @see AbstractBeanDefinition#setAutowireMode */ public void setAutowireMode(int autowireMode) { this.autowireMode = autowireMode; @@ -94,6 +97,7 @@ public int getAutowireMode() { * Set the dependency check code. * @param dependencyCheck the code to set. * Must be one of the constants defined in {@link AbstractBeanDefinition}. + * @see AbstractBeanDefinition#setDependencyCheck */ public void setDependencyCheck(int dependencyCheck) { this.dependencyCheck = dependencyCheck; @@ -108,6 +112,10 @@ public int getDependencyCheck() { /** * Set the name of the default initializer method. + *

Note that this method is not enforced on all affected bean definitions + * but rather taken as an optional callback, to be invoked if actually present. + * @see AbstractBeanDefinition#setInitMethodName + * @see AbstractBeanDefinition#setEnforceInitMethod */ public void setInitMethodName(@Nullable String initMethodName) { this.initMethodName = (StringUtils.hasText(initMethodName) ? initMethodName : null); @@ -123,6 +131,10 @@ public String getInitMethodName() { /** * Set the name of the default destroy method. + *

Note that this method is not enforced on all affected bean definitions + * but rather taken as an optional callback, to be invoked if actually present. + * @see AbstractBeanDefinition#setDestroyMethodName + * @see AbstractBeanDefinition#setEnforceDestroyMethod */ public void setDestroyMethodName(@Nullable String destroyMethodName) { this.destroyMethodName = (StringUtils.hasText(destroyMethodName) ? destroyMethodName : null); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionReaderUtils.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionReaderUtils.java index f96c96fbdc3b..b02687792e15 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionReaderUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionReaderUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -118,16 +118,13 @@ else if (definition.getFactoryBeanName() != null) { "'class' nor 'parent' nor 'factory-bean' - can't generate bean name"); } - String id = generatedBeanName; if (isInnerBean) { // Inner bean: generate identity hashcode suffix. - id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition); + return generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition); } - else { - // Top-level bean: use plain class name with unique suffix if necessary. - return uniqueBeanName(generatedBeanName, registry); - } - return id; + + // Top-level bean: use plain class name with unique suffix if necessary. + return uniqueBeanName(generatedBeanName, registry); } /** @@ -144,9 +141,10 @@ public static String uniqueBeanName(String beanName, BeanDefinitionRegistry regi int counter = -1; // Increase counter until the id is unique. + String prefix = beanName + GENERATED_BEAN_NAME_SEPARATOR; while (counter == -1 || registry.containsBeanDefinition(id)) { counter++; - id = beanName + GENERATED_BEAN_NAME_SEPARATOR + counter; + id = prefix + counter; } return id; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java index abb5040f8992..124f1fa84f8c 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -400,9 +400,10 @@ private Object resolveInnerBean(Object argName, String innerBeanName, BeanDefini private String adaptInnerBeanName(String innerBeanName) { String actualInnerBeanName = innerBeanName; int counter = 0; + String prefix = innerBeanName + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR; while (this.beanFactory.isBeanNameInUse(actualInnerBeanName)) { counter++; - actualInnerBeanName = innerBeanName + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + counter; + actualInnerBeanName = prefix + counter; } return actualInnerBeanName; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java index 88e9942e807b..698a04d2498a 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -238,8 +238,10 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp Assert.state(lo != null, "LookupOverride not found"); Object[] argsToUse = (args.length > 0 ? args : null); // if no-arg, don't insist on args at all if (StringUtils.hasText(lo.getBeanName())) { - return (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) : + Object bean = (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) : this.owner.getBean(lo.getBeanName())); + // Detect package-protected NullBean instance through equals(null) check + return (bean.equals(null) ? null : bean); } else { return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) : diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java index 8dcfff8d3ee8..db450ce00814 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,6 +66,7 @@ /** * Delegate for resolving constructors and factory methods. + * *

Performs constructor resolution through argument matching. * * @author Juergen Hoeller @@ -84,7 +85,7 @@ class ConstructorResolver { private static final Object[] EMPTY_ARGS = new Object[0]; /** - * Marker for autowired arguments in a cached argument array, to be later replaced + * Marker for autowired arguments in a cached argument array, to be replaced * by a {@linkplain #resolveAutowiredArgument resolved autowired argument}. */ private static final Object autowiredArgumentMarker = new Object(); @@ -148,7 +149,7 @@ public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, } } if (argsToResolve != null) { - argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); + argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve); } } @@ -202,21 +203,22 @@ public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, LinkedList causes = null; for (Constructor candidate : candidates) { - Class[] paramTypes = candidate.getParameterTypes(); + int parameterCount = candidate.getParameterCount(); - if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) { + if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) { // Already found greedy constructor that can be satisfied -> // do not look any further, there are only less greedy constructors left. break; } - if (paramTypes.length < minNrOfArgs) { + if (parameterCount < minNrOfArgs) { continue; } ArgumentsHolder argsHolder; + Class[] paramTypes = candidate.getParameterTypes(); if (resolvedValues != null) { try { - String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length); + String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount); if (paramNames == null) { ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { @@ -240,7 +242,7 @@ public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, } else { // Explicit arguments given -> arguments length must match exactly. - if (paramTypes.length != explicitArgs.length) { + if (parameterCount != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); @@ -274,12 +276,12 @@ else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) { throw ex; } throw new BeanCreationException(mbd.getResourceDescription(), beanName, - "Could not resolve matching constructor " + + "Could not resolve matching constructor on bean class [" + mbd.getBeanClassName() + "] " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)"); } else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, - "Ambiguous constructor matches found in bean '" + beanName + "' " + + "Ambiguous constructor matches found on bean class [" + mbd.getBeanClassName() + "] " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousConstructors); } @@ -340,7 +342,7 @@ public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) { if (uniqueCandidate == null) { uniqueCandidate = candidate; } - else if (!Arrays.equals(uniqueCandidate.getParameterTypes(), candidate.getParameterTypes())) { + else if (isParamMismatch(uniqueCandidate, candidate)) { uniqueCandidate = null; break; } @@ -349,6 +351,13 @@ else if (!Arrays.equals(uniqueCandidate.getParameterTypes(), candidate.getParame mbd.factoryMethodToIntrospect = uniqueCandidate; } + private boolean isParamMismatch(Method uniqueCandidate, Method candidate) { + int uniqueCandidateParameterCount = uniqueCandidate.getParameterCount(); + int candidateParameterCount = candidate.getParameterCount(); + return (uniqueCandidateParameterCount != candidateParameterCount || + !Arrays.equals(uniqueCandidate.getParameterTypes(), candidate.getParameterTypes())); + } + /** * Retrieve all candidate methods for the given class, considering * the {@link RootBeanDefinition#isNonPublicAccessAllowed()} flag. @@ -401,6 +410,7 @@ public BeanWrapper instantiateUsingFactoryMethod( if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { throw new ImplicitlyAppearedSingletonException(); } + this.beanFactory.registerDependentBean(factoryBeanName, beanName); factoryClass = factoryBean.getClass(); isStatic = false; } @@ -435,7 +445,7 @@ public BeanWrapper instantiateUsingFactoryMethod( } } if (argsToResolve != null) { - argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true); + argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve); } } @@ -444,27 +454,27 @@ public BeanWrapper instantiateUsingFactoryMethod( // Try all methods with this name to see if they match the given arguments. factoryClass = ClassUtils.getUserClass(factoryClass); - List candidateList = null; + List candidates = null; if (mbd.isFactoryMethodUnique) { if (factoryMethodToUse == null) { factoryMethodToUse = mbd.getResolvedFactoryMethod(); } if (factoryMethodToUse != null) { - candidateList = Collections.singletonList(factoryMethodToUse); + candidates = Collections.singletonList(factoryMethodToUse); } } - if (candidateList == null) { - candidateList = new ArrayList<>(); + if (candidates == null) { + candidates = new ArrayList<>(); Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); for (Method candidate : rawCandidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { - candidateList.add(candidate); + candidates.add(candidate); } } } - if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { - Method uniqueCandidate = candidateList.get(0); + if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { + Method uniqueCandidate = candidates.get(0); if (uniqueCandidate.getParameterCount() == 0) { mbd.factoryMethodToIntrospect = uniqueCandidate; synchronized (mbd.constructorArgumentLock) { @@ -477,8 +487,9 @@ public BeanWrapper instantiateUsingFactoryMethod( } } - Method[] candidates = candidateList.toArray(new Method[0]); - AutowireUtils.sortFactoryMethods(candidates); + if (candidates.size() > 1) { // explicitly skip immutable singletonList + candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR); + } ConstructorArgumentValues resolvedValues = null; boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); @@ -505,11 +516,12 @@ public BeanWrapper instantiateUsingFactoryMethod( LinkedList causes = null; for (Method candidate : candidates) { - Class[] paramTypes = candidate.getParameterTypes(); + int parameterCount = candidate.getParameterCount(); - if (paramTypes.length >= minNrOfArgs) { + if (parameterCount >= minNrOfArgs) { ArgumentsHolder argsHolder; + Class[] paramTypes = candidate.getParameterTypes(); if (explicitArgs != null) { // Explicit arguments given -> arguments length must match exactly. if (paramTypes.length != explicitArgs.length) { @@ -526,7 +538,7 @@ public BeanWrapper instantiateUsingFactoryMethod( paramNames = pnd.getParameterNames(candidate); } argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, - paramTypes, paramNames, candidate, autowiring, candidates.length == 1); + paramTypes, paramNames, candidate, autowiring, candidates.size() == 1); } catch (UnsatisfiedDependencyException ex) { if (logger.isTraceEnabled()) { @@ -595,7 +607,7 @@ else if (resolvedValues != null) { } String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes); throw new BeanCreationException(mbd.getResourceDescription(), beanName, - "No matching factory method found: " + + "No matching factory method found on class [" + factoryClass.getName() + "]: " + (mbd.getFactoryBeanName() != null ? "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") + "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " + @@ -606,12 +618,12 @@ else if (resolvedValues != null) { } else if (void.class == factoryMethodToUse.getReturnType()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, - "Invalid factory method '" + mbd.getFactoryMethodName() + - "': needs to have a non-void return type!"); + "Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" + + factoryClass.getName() + "]: needs to have a non-void return type!"); } else if (ambiguousFactoryMethods != null) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, - "Ambiguous factory method matches found in bean '" + beanName + "' " + + "Ambiguous factory method matches found on class [" + factoryClass.getName() + "] " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousFactoryMethods); } @@ -668,7 +680,7 @@ private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid constructor argument index: " + index); } - if (index > minNrOfArgs) { + if (index + 1 > minNrOfArgs) { minNrOfArgs = index + 1; } ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue(); @@ -805,7 +817,7 @@ private ArgumentsHolder createArgumentArray( * Resolve the prepared arguments stored in the given bean definition. */ private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, - Executable executable, Object[] argsToResolve, boolean fallback) { + Executable executable, Object[] argsToResolve) { TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); TypeConverter converter = (customConverter != null ? customConverter : bw); @@ -818,7 +830,7 @@ private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mb Object argValue = argsToResolve[argIndex]; MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex); if (argValue == autowiredArgumentMarker) { - argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback); + argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, true); } else if (argValue instanceof BeanMetadataElement) { argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 4f6dc67744bf..52c5f67aef94 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,6 @@ import javax.inject.Provider; -import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; import org.springframework.beans.TypeConverter; import org.springframework.beans.factory.BeanCreationException; @@ -97,8 +96,7 @@ * operating on pre-resolved bean definition metadata objects. * *

Note that readers for specific bean definition formats are typically - * implemented separately rather than as bean factory subclasses: - * see for example {@link PropertiesBeanDefinitionReader} and + * implemented separately rather than as bean factory subclasses: see for example * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}. * *

For an alternative implementation of the @@ -157,7 +155,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto private Comparator dependencyComparator; /** Resolver to use for checking if a bean definition is an autowire candidate. */ - private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver(); + private AutowireCandidateResolver autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE; /** Map from dependency type to corresponding autowired value. */ private final Map, Object> resolvableDependencies = new ConcurrentHashMap<>(16); @@ -165,6 +163,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto /** Map of bean definition objects, keyed by bean name. */ private final Map beanDefinitionMap = new ConcurrentHashMap<>(256); + /** Map from bean name to merged BeanDefinitionHolder. */ + private final Map mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256); + /** Map of singleton and non-singleton bean names, keyed by dependency type. */ private final Map, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64); @@ -182,7 +183,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto private volatile String[] frozenBeanDefinitionNames; /** Whether bean definition metadata may be cached for all beans. */ - private volatile boolean configurationFrozen = false; + private volatile boolean configurationFrozen; /** @@ -292,12 +293,12 @@ public Comparator getDependencyComparator() { * when deciding whether a bean definition should be considered as a * candidate for autowiring. */ - public void setAutowireCandidateResolver(final AutowireCandidateResolver autowireCandidateResolver) { + public void setAutowireCandidateResolver(AutowireCandidateResolver autowireCandidateResolver) { Assert.notNull(autowireCandidateResolver, "AutowireCandidateResolver must not be null"); if (autowireCandidateResolver instanceof BeanFactoryAware) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction) () -> { - ((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(DefaultListableBeanFactory.this); + ((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(this); return null; }, getAccessControlContext()); } @@ -324,10 +325,9 @@ public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) { this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding; this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading; this.dependencyComparator = otherListableFactory.dependencyComparator; - // A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware... - setAutowireCandidateResolver( - BeanUtils.instantiateClass(otherListableFactory.getAutowireCandidateResolver().getClass())); - // Make resolvable dependencies (e.g. ResourceLoader) available here as well... + // A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware + setAutowireCandidateResolver(otherListableFactory.getAutowireCandidateResolver().cloneIfNecessary()); + // Make resolvable dependencies (e.g. ResourceLoader) available here as well this.resolvableDependencies.putAll(otherListableFactory.resolvableDependencies); } } @@ -354,12 +354,11 @@ public T getBean(Class requiredType, @Nullable Object... args) throws Bea } @Override - public ObjectProvider getBeanProvider(Class requiredType) throws BeansException { + public ObjectProvider getBeanProvider(Class requiredType) { Assert.notNull(requiredType, "Required type must not be null"); return getBeanProvider(ResolvableType.forRawClass(requiredType)); } - @SuppressWarnings("unchecked") @Override public ObjectProvider getBeanProvider(ResolvableType requiredType) { return new BeanObjectProvider() { @@ -389,15 +388,20 @@ public T getIfAvailable() throws BeansException { public T getIfUnique() throws BeansException { return resolveBean(requiredType, null, true); } + @SuppressWarnings("unchecked") @Override public Stream stream() { return Arrays.stream(getBeanNamesForTypedStream(requiredType)) .map(name -> (T) getBean(name)) .filter(bean -> !(bean instanceof NullBean)); } + @SuppressWarnings("unchecked") @Override public Stream orderedStream() { String[] beanNames = getBeanNamesForTypedStream(requiredType); + if (beanNames.length == 0) { + return Stream.empty(); + } Map matchingBeans = new LinkedHashMap<>(beanNames.length); for (String beanName : beanNames) { Object beanInstance = getBean(beanName); @@ -473,10 +477,10 @@ public String[] getBeanNamesForType(ResolvableType type) { public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { Class resolved = type.resolve(); if (resolved != null && !type.hasGenerics()) { - return getBeanNamesForType(resolved, includeNonSingletons, includeNonSingletons); + return getBeanNamesForType(resolved, includeNonSingletons, allowEagerInit); } else { - return doGetBeanNamesForType(type, includeNonSingletons, includeNonSingletons); + return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit); } } @@ -508,8 +512,7 @@ private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSi // Check all bean definitions. for (String beanName : this.beanDefinitionNames) { - // Only consider bean as eligible if the bean name - // is not defined as alias for some other bean. + // Only consider bean as eligible if the bean name is not defined as alias for some other bean. if (!isAlias(beanName)) { try { RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); @@ -520,14 +523,14 @@ private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSi boolean isFactoryBean = isFactoryBean(beanName, mbd); BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); boolean matchFound = false; - boolean allowFactoryBeanInit = allowEagerInit || containsSingleton(beanName); - boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit(); + boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName)); + boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit()); if (!isFactoryBean) { if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) { matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); } } - else { + else { if (includeNonSingletons || isNonLazyDecorated || (allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) { matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); @@ -548,16 +551,19 @@ private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSi throw ex; } // Probably a placeholder: let's ignore it for type matching purposes. - LogMessage message = (ex instanceof CannotLoadBeanClassException) ? + LogMessage message = (ex instanceof CannotLoadBeanClassException ? LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) : - LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName); + LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName)); logger.trace(message, ex); + // Register exception, in case the bean was accidentally unresolvable. onSuppressedException(ex); } + catch (NoSuchBeanDefinitionException ex) { + // Bean definition got removed while we were iterating -> ignore. + } } } - // Check manually registered singletons too. for (String beanName : this.manualSingletonNames) { try { @@ -578,7 +584,8 @@ private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSi } catch (NoSuchBeanDefinitionException ex) { // Shouldn't happen - probably a result of circular reference resolution... - logger.trace(LogMessage.format("Failed to check manually registered singleton with name '%s'", beanName), ex); + logger.trace(LogMessage.format( + "Failed to check manually registered singleton with name '%s'", beanName), ex); } } @@ -607,8 +614,8 @@ public Map getBeansOfType(@Nullable Class type) throws BeansEx @Override @SuppressWarnings("unchecked") - public Map getBeansOfType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit) - throws BeansException { + public Map getBeansOfType( + @Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException { String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit); Map result = new LinkedHashMap<>(beanNames.length); @@ -645,8 +652,8 @@ public Map getBeansOfType(@Nullable Class type, boolean includ public String[] getBeanNamesForAnnotation(Class annotationType) { List result = new ArrayList<>(); for (String beanName : this.beanDefinitionNames) { - BeanDefinition beanDefinition = getBeanDefinition(beanName); - if (!beanDefinition.isAbstract() && findAnnotationOnBean(beanName, annotationType) != null) { + BeanDefinition bd = this.beanDefinitionMap.get(beanName); + if (bd != null && !bd.isAbstract() && findAnnotationOnBean(beanName, annotationType) != null) { result.add(beanName); } } @@ -749,12 +756,13 @@ public boolean isAutowireCandidate(String beanName, DependencyDescriptor descrip * @param resolver the AutowireCandidateResolver to use for the actual resolution algorithm * @return whether the bean should be considered as autowire candidate */ - protected boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver) + protected boolean isAutowireCandidate( + String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver) throws NoSuchBeanDefinitionException { - String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName); - if (containsBeanDefinition(beanDefinitionName)) { - return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(beanDefinitionName), descriptor, resolver); + String bdName = BeanFactoryUtils.transformedBeanName(beanName); + if (containsBeanDefinition(bdName)) { + return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(bdName), descriptor, resolver); } else if (containsSingleton(beanName)) { return isAutowireCandidate(beanName, new RootBeanDefinition(getType(beanName)), descriptor, resolver); @@ -786,13 +794,16 @@ else if (parent instanceof ConfigurableListableBeanFactory) { protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd, DependencyDescriptor descriptor, AutowireCandidateResolver resolver) { - String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName); - resolveBeanClass(mbd, beanDefinitionName); + String bdName = BeanFactoryUtils.transformedBeanName(beanName); + resolveBeanClass(mbd, bdName); if (mbd.isFactoryMethodUnique && mbd.factoryMethodToIntrospect == null) { new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd); } - return resolver.isAutowireCandidate( - new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)), descriptor); + BeanDefinitionHolder holder = (beanName.equals(bdName) ? + this.mergedBeanDefinitionHolders.computeIfAbsent(beanName, + key -> new BeanDefinitionHolder(mbd, beanName, getAliases(bdName))) : + new BeanDefinitionHolder(mbd, beanName, getAliases(bdName))); + return resolver.isAutowireCandidate(holder, descriptor); } @Override @@ -815,9 +826,16 @@ public Iterator getBeanNamesIterator() { return iterator; } + @Override + protected void clearMergedBeanDefinition(String beanName) { + super.clearMergedBeanDefinition(beanName); + this.mergedBeanDefinitionHolders.remove(beanName); + } + @Override public void clearMetadataCache() { super.clearMetadataCache(); + this.mergedBeanDefinitionHolders.clear(); clearByTypeCache(); } @@ -859,11 +877,11 @@ public void preInstantiateSingletons() throws BeansException { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { - final FactoryBean factory = (FactoryBean) bean; + FactoryBean factory = (FactoryBean) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { - isEagerInit = AccessController.doPrivileged((PrivilegedAction) - ((SmartFactoryBean) factory)::isEagerInit, + isEagerInit = AccessController.doPrivileged( + (PrivilegedAction) ((SmartFactoryBean) factory)::isEagerInit, getAccessControlContext()); } else { @@ -885,7 +903,7 @@ public void preInstantiateSingletons() throws BeansException { for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { - final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; + SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction) () -> { smartSingleton.afterSingletonsInstantiated(); @@ -974,6 +992,9 @@ else if (!beanDefinition.equals(existingDefinition)) { if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } + else if (isConfigurationFrozen()) { + clearByTypeCache(); + } } @Override @@ -1036,8 +1057,7 @@ protected void resetBeanDefinition(String beanName) { for (String bdName : this.beanDefinitionNames) { if (!beanName.equals(bdName)) { BeanDefinition bd = this.beanDefinitionMap.get(bdName); - // Ensure bd is non-null due to potential concurrent modification - // of the beanDefinitionMap. + // Ensure bd is non-null due to potential concurrent modification of beanDefinitionMap. if (bd != null && beanName.equals(bd.getParentName())) { resetBeanDefinition(bdName); } @@ -1307,7 +1327,7 @@ public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable Str private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) { - final Class type = descriptor.getDependencyType(); + Class type = descriptor.getDependencyType(); if (descriptor instanceof StreamDependencyDescriptor) { Map matchingBeans = findAutowireCandidates(beanName, type, descriptor); @@ -1366,9 +1386,11 @@ else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); Object result = converter.convertIfNecessary(matchingBeans.values(), type); if (result instanceof List) { - Comparator comparator = adaptDependencyComparator(matchingBeans); - if (comparator != null) { - ((List) result).sort(comparator); + if (((List) result).size() > 1) { + Comparator comparator = adaptDependencyComparator(matchingBeans); + if (comparator != null) { + ((List) result).sort(comparator); + } } } return result; @@ -1701,18 +1723,23 @@ private void raiseNoMatchingBeanFound( */ private void checkBeanNotOfRequiredType(Class type, DependencyDescriptor descriptor) { for (String beanName : this.beanDefinitionNames) { - RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); - Class targetType = mbd.getTargetType(); - if (targetType != null && type.isAssignableFrom(targetType) && - isAutowireCandidate(beanName, mbd, descriptor, getAutowireCandidateResolver())) { - // Probably a proxy interfering with target type match -> throw meaningful exception. - Object beanInstance = getSingleton(beanName, false); - Class beanType = (beanInstance != null && beanInstance.getClass() != NullBean.class ? - beanInstance.getClass() : predictBeanType(beanName, mbd)); - if (beanType != null && !type.isAssignableFrom(beanType)) { - throw new BeanNotOfRequiredTypeException(beanName, type, beanType); + try { + RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); + Class targetType = mbd.getTargetType(); + if (targetType != null && type.isAssignableFrom(targetType) && + isAutowireCandidate(beanName, mbd, descriptor, getAutowireCandidateResolver())) { + // Probably a proxy interfering with target type match -> throw meaningful exception. + Object beanInstance = getSingleton(beanName, false); + Class beanType = (beanInstance != null && beanInstance.getClass() != NullBean.class ? + beanInstance.getClass() : predictBeanType(beanName, mbd)); + if (beanType != null && !type.isAssignableFrom(beanType)) { + throw new BeanNotOfRequiredTypeException(beanName, type, beanType); + } } } + catch (NoSuchBeanDefinitionException ex) { + // Bean definition got removed while we were iterating -> ignore. + } } BeanFactory parent = getParentBeanFactory(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java index 737566691260..0a81aef4e9fe 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -70,6 +70,10 @@ */ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { + /** Maximum number of suppressed exceptions to preserve. */ + private static final int SUPPRESSED_EXCEPTIONS_LIMIT = 100; + + /** Cache of singleton objects: bean name to bean instance. */ private final Map singletonObjects = new ConcurrentHashMap<>(256); @@ -77,7 +81,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements private final Map> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ - private final Map earlySingletonObjects = new HashMap<>(16); + private final Map earlySingletonObjects = new ConcurrentHashMap<>(16); /** Set of registered singletons, containing the bean names in registration order. */ private final Set registeredSingletons = new LinkedHashSet<>(256); @@ -90,7 +94,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements private final Set inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); - /** List of suppressed Exceptions, available for associating related causes. */ + /** Collection of suppressed Exceptions, available for associating related causes. */ @Nullable private Set suppressedExceptions; @@ -174,16 +178,24 @@ public Object getSingleton(String beanName) { */ @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { + // Quick check for existing instance without full singleton lock Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { - synchronized (this.singletonObjects) { - singletonObject = this.earlySingletonObjects.get(beanName); - if (singletonObject == null && allowEarlyReference) { - ObjectFactory singletonFactory = this.singletonFactories.get(beanName); - if (singletonFactory != null) { - singletonObject = singletonFactory.getObject(); - this.earlySingletonObjects.put(beanName, singletonObject); - this.singletonFactories.remove(beanName); + singletonObject = this.earlySingletonObjects.get(beanName); + if (singletonObject == null && allowEarlyReference) { + synchronized (this.singletonObjects) { + // Consistent creation of early reference within full singleton lock + singletonObject = this.singletonObjects.get(beanName); + if (singletonObject == null) { + singletonObject = this.earlySingletonObjects.get(beanName); + if (singletonObject == null) { + ObjectFactory singletonFactory = this.singletonFactories.get(beanName); + if (singletonFactory != null) { + singletonObject = singletonFactory.getObject(); + this.earlySingletonObjects.put(beanName, singletonObject); + this.singletonFactories.remove(beanName); + } + } } } } @@ -253,13 +265,17 @@ public Object getSingleton(String beanName, ObjectFactory singletonFactory) { } /** - * Register an Exception that happened to get suppressed during the creation of a + * Register an exception that happened to get suppressed during the creation of a * singleton bean instance, e.g. a temporary circular reference resolution problem. + *

The default implementation preserves any given exception in this registry's + * collection of suppressed exceptions, up to a limit of 100 exceptions, adding + * them as related causes to an eventual top-level {@link BeanCreationException}. * @param ex the Exception to register + * @see BeanCreationException#getRelatedCauses() */ protected void onSuppressedException(Exception ex) { synchronized (this.singletonObjects) { - if (this.suppressedExceptions != null) { + if (this.suppressedExceptions != null && this.suppressedExceptions.size() < SUPPRESSED_EXCEPTIONS_LIMIT) { this.suppressedExceptions.add(ex); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java index 36768418cdd8..98d2601fd176 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,6 +62,8 @@ @SuppressWarnings("serial") class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { + private static final String DESTROY_METHOD_NAME = "destroy"; + private static final String CLOSE_METHOD_NAME = "close"; private static final String SHUTDOWN_METHOD_NAME = "shutdown"; @@ -87,7 +89,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { private transient Method destroyMethod; @Nullable - private List beanPostProcessors; + private final List beanPostProcessors; /** @@ -104,13 +106,16 @@ public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition be Assert.notNull(bean, "Disposable bean must not be null"); this.bean = bean; this.beanName = beanName; - this.invokeDisposableBean = - (this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy")); + this.invokeDisposableBean = (bean instanceof DisposableBean && + !beanDefinition.isExternallyManagedDestroyMethod(DESTROY_METHOD_NAME)); this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed(); this.acc = acc; + String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition); - if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) && + if (destroyMethodName != null && + !(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodName)) && !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { + this.destroyMethodName = destroyMethodName; Method destroyMethod = determineDestroyMethod(destroyMethodName); if (destroyMethod == null) { @@ -120,19 +125,22 @@ public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition be } } else { - Class[] paramTypes = destroyMethod.getParameterTypes(); - if (paramTypes.length > 1) { - throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" + - beanName + "' has more than one parameter - not supported as destroy method"); - } - else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) { - throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" + - beanName + "' has a non-boolean parameter - not supported as destroy method"); + if (destroyMethod.getParameterCount() > 0) { + Class[] paramTypes = destroyMethod.getParameterTypes(); + if (paramTypes.length > 1) { + throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" + + beanName + "' has more than one parameter - not supported as destroy method"); + } + else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) { + throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" + + beanName + "' has a non-boolean parameter - not supported as destroy method"); + } } destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod); } this.destroyMethod = destroyMethod; } + this.beanPostProcessors = filterPostProcessors(postProcessors, bean); } @@ -169,67 +177,6 @@ private DisposableBeanAdapter(Object bean, String beanName, boolean invokeDispos } - /** - * If the current value of the given beanDefinition's "destroyMethodName" property is - * {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method. - * Candidate methods are currently limited to public, no-arg methods named "close" or - * "shutdown" (whether declared locally or inherited). The given BeanDefinition's - * "destroyMethodName" is updated to be null if no such method is found, otherwise set - * to the name of the inferred method. This constant serves as the default for the - * {@code @Bean#destroyMethod} attribute and the value of the constant may also be - * used in XML within the {@code } or {@code - * } attributes. - *

Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable} - * interfaces, reflectively calling the "close" method on implementing beans as well. - */ - @Nullable - private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) { - String destroyMethodName = beanDefinition.getDestroyMethodName(); - if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) || - (destroyMethodName == null && bean instanceof AutoCloseable)) { - // Only perform destroy method inference or Closeable detection - // in case of the bean not explicitly implementing DisposableBean - if (!(bean instanceof DisposableBean)) { - try { - return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName(); - } - catch (NoSuchMethodException ex) { - try { - return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName(); - } - catch (NoSuchMethodException ex2) { - // no candidate destroy method found - } - } - } - return null; - } - return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null); - } - - /** - * Search for all DestructionAwareBeanPostProcessors in the List. - * @param processors the List to search - * @return the filtered List of DestructionAwareBeanPostProcessors - */ - @Nullable - private List filterPostProcessors(List processors, Object bean) { - List filteredPostProcessors = null; - if (!CollectionUtils.isEmpty(processors)) { - filteredPostProcessors = new ArrayList<>(processors.size()); - for (BeanPostProcessor processor : processors) { - if (processor instanceof DestructionAwareBeanPostProcessor) { - DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor; - if (dabpp.requiresDestruction(bean)) { - filteredPostProcessors.add(dabpp); - } - } - } - } - return filteredPostProcessors; - } - - @Override public void run() { destroy(); @@ -311,9 +258,9 @@ private Method findDestroyMethod(String name) { * assuming a "force" parameter), else logging an error. */ private void invokeCustomDestroyMethod(final Method destroyMethod) { - Class[] paramTypes = destroyMethod.getParameterTypes(); - final Object[] args = new Object[paramTypes.length]; - if (paramTypes.length == 1) { + int paramCount = destroyMethod.getParameterCount(); + final Object[] args = new Object[paramCount]; + if (paramCount == 1) { args[0] = Boolean.TRUE; } if (logger.isTraceEnabled()) { @@ -384,12 +331,50 @@ public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefin if (bean instanceof DisposableBean || bean instanceof AutoCloseable) { return true; } - String destroyMethodName = beanDefinition.getDestroyMethodName(); - if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) { - return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) || - ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME)); + return inferDestroyMethodIfNecessary(bean, beanDefinition) != null; + } + + + /** + * If the current value of the given beanDefinition's "destroyMethodName" property is + * {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method. + * Candidate methods are currently limited to public, no-arg methods named "close" or + * "shutdown" (whether declared locally or inherited). The given BeanDefinition's + * "destroyMethodName" is updated to be null if no such method is found, otherwise set + * to the name of the inferred method. This constant serves as the default for the + * {@code @Bean#destroyMethod} attribute and the value of the constant may also be + * used in XML within the {@code } or {@code + * } attributes. + *

Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable} + * interfaces, reflectively calling the "close" method on implementing beans as well. + */ + @Nullable + private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) { + String destroyMethodName = beanDefinition.resolvedDestroyMethodName; + if (destroyMethodName == null) { + destroyMethodName = beanDefinition.getDestroyMethodName(); + if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) || + (destroyMethodName == null && bean instanceof AutoCloseable)) { + // Only perform destroy method inference in case of the bean + // not explicitly implementing the DisposableBean interface + destroyMethodName = null; + if (!(bean instanceof DisposableBean)) { + try { + destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName(); + } + catch (NoSuchMethodException ex) { + try { + destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName(); + } + catch (NoSuchMethodException ex2) { + // no candidate destroy method found + } + } + } + } + beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : ""); } - return StringUtils.hasLength(destroyMethodName); + return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null); } /** @@ -411,4 +396,26 @@ public static boolean hasApplicableProcessors(Object bean, List filterPostProcessors(List processors, Object bean) { + List filteredPostProcessors = null; + if (!CollectionUtils.isEmpty(processors)) { + filteredPostProcessors = new ArrayList<>(processors.size()); + for (BeanPostProcessor processor : processors) { + if (processor instanceof DestructionAwareBeanPostProcessor) { + DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor; + if (dabpp.requiresDestruction(bean)) { + filteredPostProcessors.add(dabpp); + } + } + } + } + return filteredPostProcessors; + } + } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java index ce865d11305f..fc689a7aec32 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,11 +54,11 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg * or {@code null} if the type cannot be determined yet */ @Nullable - protected Class getTypeForFactoryBean(final FactoryBean factoryBean) { + protected Class getTypeForFactoryBean(FactoryBean factoryBean) { try { if (System.getSecurityManager() != null) { - return AccessController.doPrivileged((PrivilegedAction>) - factoryBean::getObjectType, getAccessControlContext()); + return AccessController.doPrivileged( + (PrivilegedAction>) factoryBean::getObjectType, getAccessControlContext()); } else { return factoryBean.getObjectType(); @@ -153,9 +153,7 @@ protected Object getObjectFromFactoryBean(FactoryBean factory, String beanNam * @throws BeanCreationException if FactoryBean object creation failed * @see org.springframework.beans.factory.FactoryBean#getObject() */ - private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName) - throws BeanCreationException { - + private Object doGetObjectFromFactoryBean(FactoryBean factory, String beanName) throws BeanCreationException { Object object; try { if (System.getSecurityManager() != null) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java index 7143fc9b1fa1..01b81450903d 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ * @since 4.0 */ public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCandidateResolver - implements BeanFactoryAware { + implements BeanFactoryAware, Cloneable { @Nullable private BeanFactory beanFactory; @@ -177,4 +177,21 @@ protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, D return null; } + + /** + * This implementation clones all instance fields through standard + * {@link Cloneable} support, allowing for subsequent reconfiguration + * of the cloned instance through a fresh {@link #setBeanFactory} call. + * @see #clone() + */ + @Override + public AutowireCandidateResolver cloneIfNecessary() { + try { + return (AutowireCandidateResolver) clone(); + } + catch (CloneNotSupportedException ex) { + throw new IllegalStateException(ex); + } + } + } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java index 2e620dc11a00..362f7ac2df4c 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.springframework.beans.PropertyAccessor; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.CannotLoadBeanClassException; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.core.io.Resource; @@ -367,7 +368,7 @@ public int registerBeanDefinitions(Map map, @Nullable String prefix, Strin // Key is of form: prefix.property String nameAndProperty = keyString.substring(prefix.length()); // Find dot before property name, ignoring dots in property keys. - int sepIdx = -1; + int sepIdx ; int propKeyIdx = nameAndProperty.indexOf(PropertyAccessor.PROPERTY_KEY_PREFIX); if (propKeyIdx != -1) { sepIdx = nameAndProperty.lastIndexOf(SEPARATOR, propKeyIdx); @@ -414,17 +415,20 @@ protected void registerBeanDefinition(String beanName, Map map, String pre String className = null; String parent = null; - String scope = GenericBeanDefinition.SCOPE_SINGLETON; + String scope = BeanDefinition.SCOPE_SINGLETON; boolean isAbstract = false; boolean lazyInit = false; ConstructorArgumentValues cas = new ConstructorArgumentValues(); MutablePropertyValues pvs = new MutablePropertyValues(); + String prefixWithSep = prefix + SEPARATOR; + int beginIndex = prefixWithSep.length(); + for (Map.Entry entry : map.entrySet()) { String key = StringUtils.trimWhitespace((String) entry.getKey()); - if (key.startsWith(prefix + SEPARATOR)) { - String property = key.substring(prefix.length() + SEPARATOR.length()); + if (key.startsWith(prefixWithSep)) { + String property = key.substring(beginIndex); if (CLASS_KEY.equals(property)) { className = StringUtils.trimWhitespace((String) entry.getValue()); } @@ -442,8 +446,8 @@ else if (SCOPE_KEY.equals(property)) { else if (SINGLETON_KEY.equals(property)) { // Spring 1.2 style String val = StringUtils.trimWhitespace((String) entry.getValue()); - scope = ("".equals(val) || TRUE_VALUE.equals(val) ? GenericBeanDefinition.SCOPE_SINGLETON : - GenericBeanDefinition.SCOPE_PROTOTYPE); + scope = (!StringUtils.hasLength(val) || TRUE_VALUE.equals(val) ? + BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE); } else if (LAZY_INIT_KEY.equals(property)) { String val = StringUtils.trimWhitespace((String) entry.getValue()); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ReplaceOverride.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ReplaceOverride.java index c94ce6717628..1b51bf706553 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ReplaceOverride.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ReplaceOverride.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ package org.springframework.beans.factory.support; import java.lang.reflect.Method; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import org.springframework.lang.Nullable; @@ -39,7 +39,7 @@ public class ReplaceOverride extends MethodOverride { private final String methodReplacerBeanName; - private List typeIdentifiers = new LinkedList<>(); + private final List typeIdentifiers = new ArrayList<>(); /** @@ -49,7 +49,7 @@ public class ReplaceOverride extends MethodOverride { */ public ReplaceOverride(String methodName, String methodReplacerBeanName) { super(methodName); - Assert.notNull(methodName, "Method replacer bean name must not be null"); + Assert.notNull(methodReplacerBeanName, "Method replacer bean name must not be null"); this.methodReplacerBeanName = methodReplacerBeanName; } @@ -70,6 +70,7 @@ public void addTypeIdentifier(String identifier) { this.typeIdentifiers.add(identifier); } + @Override public boolean matches(Method method) { if (!method.getName().equals(getMethodName())) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java index 8422ad309ebf..863873499266 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition { boolean allowCaching = true; - boolean isFactoryMethodUnique = false; + boolean isFactoryMethodUnique; @Nullable volatile ResolvableType targetType; @@ -86,6 +86,10 @@ public class RootBeanDefinition extends AbstractBeanDefinition { @Nullable volatile Method factoryMethodToIntrospect; + /** Package-visible field for caching a resolved destroy method name (also for inferred). */ + @Nullable + volatile String resolvedDestroyMethodName; + /** Common lock for the four constructor fields below. */ final Object constructorArgumentLock = new Object(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java index 17909b5946b9..f33eeecf16aa 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,13 @@ */ public class SimpleAutowireCandidateResolver implements AutowireCandidateResolver { + /** + * Shared instance of {@code SimpleAutowireCandidateResolver}. + * @since 5.2.7 + */ + public static final SimpleAutowireCandidateResolver INSTANCE = new SimpleAutowireCandidateResolver(); + + @Override public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) { return bdHolder.getBeanDefinition().isAutowireCandidate(); @@ -40,6 +47,11 @@ public boolean isRequired(DependencyDescriptor descriptor) { return descriptor.isRequired(); } + @Override + public boolean hasQualifier(DependencyDescriptor descriptor) { + return false; + } + @Override @Nullable public Object getSuggestedValue(DependencyDescriptor descriptor) { @@ -52,4 +64,13 @@ public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, return null; } + /** + * This implementation returns {@code this} as-is. + * @see #INSTANCE + */ + @Override + public AutowireCandidateResolver cloneIfNecessary() { + return this; + } + } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java index 7d77a45b0d71..25c4cd59c550 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +37,7 @@ import org.springframework.beans.factory.SmartFactoryBean; import org.springframework.core.OrderComparator; import org.springframework.core.ResolvableType; -import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -45,20 +45,22 @@ /** * Static {@link org.springframework.beans.factory.BeanFactory} implementation - * which allows to register existing singleton instances programmatically. - * Does not have support for prototype beans or aliases. + * which allows one to register existing singleton instances programmatically. * - *

Serves as example for a simple implementation of the + *

Does not have support for prototype beans or aliases. + * + *

Serves as an example for a simple implementation of the * {@link org.springframework.beans.factory.ListableBeanFactory} interface, * managing existing bean instances rather than creating new ones based on bean * definitions, and not implementing any extended SPI interfaces (such as * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}). * - *

For a full-fledged factory based on bean definitions, have a look - * at {@link DefaultListableBeanFactory}. + *

For a full-fledged factory based on bean definitions, have a look at + * {@link DefaultListableBeanFactory}. * * @author Rod Johnson * @author Juergen Hoeller + * @author Sam Brannen * @since 06.01.2003 * @see DefaultListableBeanFactory */ @@ -83,7 +85,7 @@ public StaticListableBeanFactory() { * or {@link java.util.Collections#emptyMap()} for a dummy factory which * enforces operating against an empty set of beans. * @param beans a {@code Map} for holding this factory's beans, with the - * bean name String as key and the corresponding singleton object as value + * bean name as key and the corresponding singleton object as value * @since 4.3 */ public StaticListableBeanFactory(Map beans) { @@ -94,7 +96,7 @@ public StaticListableBeanFactory(Map beans) { /** * Add a new singleton bean. - * Will overwrite any existing instance for the given name. + *

Will overwrite any existing instance for the given name. * @param name the name of the bean * @param bean the bean instance */ @@ -262,7 +264,10 @@ public boolean containsBean(String name) { public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { Object bean = getBean(name); // In case of FactoryBean, return singleton status of created object. - return (bean instanceof FactoryBean && ((FactoryBean) bean).isSingleton()); + if (bean instanceof FactoryBean) { + return ((FactoryBean) bean).isSingleton(); + } + return true; } @Override @@ -337,7 +342,6 @@ public String[] getBeanNamesForType(@Nullable ResolvableType type) { return getBeanNamesForType(type, true, true); } - @Override public String[] getBeanNamesForType(@Nullable ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { @@ -446,7 +450,7 @@ public A findAnnotationOnBean(String beanName, Class a throws NoSuchBeanDefinitionException { Class beanType = getType(beanName); - return (beanType != null ? AnnotationUtils.findAnnotation(beanType, annotationType) : null); + return (beanType != null ? AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType) : null); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java index 4fd5ccdd6011..6be311eb1efe 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -90,7 +90,7 @@ public class BeanDefinitionParserDelegate { /** * Value of a T/F attribute that represents true. - * Anything else represents false. Case seNsItive. + * Anything else represents false. */ public static final String TRUE_VALUE = "true"; @@ -1523,7 +1523,7 @@ public boolean nodeNameEquals(Node node, String desiredName) { * Determine whether the given URI indicates the default namespace. */ public boolean isDefaultNamespace(@Nullable String namespaceUri) { - return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri)); + return !StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri); } /** @@ -1534,7 +1534,7 @@ public boolean isDefaultNamespace(Node node) { } private boolean isDefaultValue(String value) { - return (DEFAULT_VALUE.equals(value) || "".equals(value)); + return !StringUtils.hasLength(value) || DEFAULT_VALUE.equals(value); } private boolean isCandidateElement(Node node) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java index 2223f789ae1c..4bd6ef58e966 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,24 +64,24 @@ public ParserContext(XmlReaderContext readerContext, BeanDefinitionParserDelegat } - public final XmlReaderContext getReaderContext() { + public XmlReaderContext getReaderContext() { return this.readerContext; } - public final BeanDefinitionRegistry getRegistry() { + public BeanDefinitionRegistry getRegistry() { return this.readerContext.getRegistry(); } - public final BeanDefinitionParserDelegate getDelegate() { + public BeanDefinitionParserDelegate getDelegate() { return this.delegate; } @Nullable - public final BeanDefinition getContainingBeanDefinition() { + public BeanDefinition getContainingBeanDefinition() { return this.containingBeanDefinition; } - public final boolean isNested() { + public boolean isNested() { return (this.containingBeanDefinition != null); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java index 05501d3ce0dd..589208a4d3af 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -128,7 +128,12 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { private final XmlValidationModeDetector validationModeDetector = new XmlValidationModeDetector(); private final ThreadLocal> resourcesCurrentlyBeingLoaded = - new NamedThreadLocal<>("XML bean definition resources currently being loaded"); + new NamedThreadLocal>("XML bean definition resources currently being loaded"){ + @Override + protected Set initialValue() { + return new HashSet<>(4); + } + }; /** @@ -319,26 +324,18 @@ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefin } Set currentResources = this.resourcesCurrentlyBeingLoaded.get(); - if (currentResources == null) { - currentResources = new HashSet<>(4); - this.resourcesCurrentlyBeingLoaded.set(currentResources); - } + if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } - try { - InputStream inputStream = encodedResource.getResource().getInputStream(); - try { - InputSource inputSource = new InputSource(inputStream); - if (encodedResource.getEncoding() != null) { - inputSource.setEncoding(encodedResource.getEncoding()); - } - return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); - } - finally { - inputStream.close(); + + try (InputStream inputStream = encodedResource.getResource().getInputStream()) { + InputSource inputSource = new InputSource(inputStream); + if (encodedResource.getEncoding() != null) { + inputSource.setEncoding(encodedResource.getEncoding()); } + return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } catch (IOException ex) { throw new BeanDefinitionStoreException( diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/PathEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/PathEditor.java index f1edae00c793..0ee0f5e80f60 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/PathEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/PathEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,8 +26,8 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceEditor; -import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; +import org.springframework.util.ResourceUtils; /** * Editor for {@code java.nio.file.Path}, to directly populate a Path @@ -74,7 +74,7 @@ public PathEditor(ResourceEditor resourceEditor) { @Override public void setAsText(String text) throws IllegalArgumentException { - boolean nioPathCandidate = !text.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX); + boolean nioPathCandidate = !text.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX); if (nioPathCandidate && !text.startsWith("/")) { try { URI uri = new URI(text); @@ -85,9 +85,13 @@ public void setAsText(String text) throws IllegalArgumentException { return; } } - catch (URISyntaxException | FileSystemNotFoundException ex) { - // Not a valid URI (let's try as Spring resource location), - // or a URI scheme not registered for NIO (let's try URL + catch (URISyntaxException ex) { + // Not a valid URI; potentially a Windows-style path after + // a file prefix (let's try as Spring resource location) + nioPathCandidate = !text.startsWith(ResourceUtils.FILE_URL_PREFIX); + } + catch (FileSystemNotFoundException ex) { + // URI scheme not registered for NIO (let's try URL // protocol handlers via Spring's resource mechanism). } } @@ -97,7 +101,7 @@ public void setAsText(String text) throws IllegalArgumentException { if (resource == null) { setValue(null); } - else if (!resource.exists() && nioPathCandidate) { + else if (nioPathCandidate && !resource.exists()) { setValue(Paths.get(text).normalize()); } else { diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java index eee219ed9e8f..1a7a8ccc24f8 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,7 +53,7 @@ public class StringArrayPropertyEditor extends PropertyEditorSupport { /** - * Create a new StringArrayPropertyEditor with the default separator + * Create a new {@code StringArrayPropertyEditor} with the default separator * (a comma). *

An empty text (without elements) will be turned into an empty array. */ @@ -62,7 +62,7 @@ public StringArrayPropertyEditor() { } /** - * Create a new StringArrayPropertyEditor with the given separator. + * Create a new {@code StringArrayPropertyEditor} with the given separator. *

An empty text (without elements) will be turned into an empty array. * @param separator the separator to use for splitting a {@link String} */ @@ -71,7 +71,7 @@ public StringArrayPropertyEditor(String separator) { } /** - * Create a new StringArrayPropertyEditor with the given separator. + * Create a new {@code StringArrayPropertyEditor} with the given separator. * @param separator the separator to use for splitting a {@link String} * @param emptyArrayAsNull {@code true} if an empty String array * is to be transformed into {@code null} @@ -81,19 +81,19 @@ public StringArrayPropertyEditor(String separator, boolean emptyArrayAsNull) { } /** - * Create a new StringArrayPropertyEditor with the given separator. + * Create a new {@code StringArrayPropertyEditor} with the given separator. * @param separator the separator to use for splitting a {@link String} * @param emptyArrayAsNull {@code true} if an empty String array * is to be transformed into {@code null} * @param trimValues {@code true} if the values in the parsed arrays - * are to be trimmed of whitespace (default is true). + * are to be trimmed of whitespace (default is true) */ public StringArrayPropertyEditor(String separator, boolean emptyArrayAsNull, boolean trimValues) { this(separator, null, emptyArrayAsNull, trimValues); } /** - * Create a new StringArrayPropertyEditor with the given separator. + * Create a new {@code StringArrayPropertyEditor} with the given separator. * @param separator the separator to use for splitting a {@link String} * @param charsToDelete a set of characters to delete, in addition to * trimming an input String. Useful for deleting unwanted line breaks: @@ -106,7 +106,7 @@ public StringArrayPropertyEditor(String separator, @Nullable String charsToDelet } /** - * Create a new StringArrayPropertyEditor with the given separator. + * Create a new {@code StringArrayPropertyEditor} with the given separator. * @param separator the separator to use for splitting a {@link String} * @param charsToDelete a set of characters to delete, in addition to * trimming an input String. Useful for deleting unwanted line breaks: @@ -114,7 +114,7 @@ public StringArrayPropertyEditor(String separator, @Nullable String charsToDelet * @param emptyArrayAsNull {@code true} if an empty String array * is to be transformed into {@code null} * @param trimValues {@code true} if the values in the parsed arrays - * are to be trimmed of whitespace (default is true). + * are to be trimmed of whitespace (default is true) */ public StringArrayPropertyEditor( String separator, @Nullable String charsToDelete, boolean emptyArrayAsNull, boolean trimValues) { @@ -128,13 +128,13 @@ public StringArrayPropertyEditor( @Override public void setAsText(String text) throws IllegalArgumentException { String[] array = StringUtils.delimitedListToStringArray(text, this.separator, this.charsToDelete); - if (this.trimValues) { - array = StringUtils.trimArrayElements(array); - } if (this.emptyArrayAsNull && array.length == 0) { setValue(null); } else { + if (this.trimValues) { + array = StringUtils.trimArrayElements(array); + } setValue(array); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java index 8327653c456a..344fb5d439f9 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -119,7 +119,7 @@ public void setAsText(String text) throws IllegalArgumentException { setValue(createURI(uri)); } catch (URISyntaxException ex) { - throw new IllegalArgumentException("Invalid URI syntax: " + ex); + throw new IllegalArgumentException("Invalid URI syntax: " + ex.getMessage()); } } } diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/UUIDEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/UUIDEditor.java index 6c2e9ced7c14..895c6cb20fb8 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/UUIDEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/UUIDEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,7 @@ public class UUIDEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { if (StringUtils.hasText(text)) { - setValue(UUID.fromString(text)); + setValue(UUID.fromString(text.trim())); } else { setValue(null); diff --git a/spring-beans/src/main/java/org/springframework/beans/support/ArgumentConvertingMethodInvoker.java b/spring-beans/src/main/java/org/springframework/beans/support/ArgumentConvertingMethodInvoker.java index 006da60e4d03..bdd72f24d380 100644 --- a/spring-beans/src/main/java/org/springframework/beans/support/ArgumentConvertingMethodInvoker.java +++ b/spring-beans/src/main/java/org/springframework/beans/support/ArgumentConvertingMethodInvoker.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -146,8 +146,9 @@ protected Method doFindMatchingMethod(Object[] arguments) { for (Method candidate : candidates) { if (candidate.getName().equals(targetMethod)) { // Check if the inspected method has the correct number of parameters. - Class[] paramTypes = candidate.getParameterTypes(); - if (paramTypes.length == argCount) { + int parameterCount = candidate.getParameterCount(); + if (parameterCount == argCount) { + Class[] paramTypes = candidate.getParameterTypes(); Object[] convertedArguments = new Object[argCount]; boolean match = true; for (int j = 0; j < argCount && match; j++) { diff --git a/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyAccessorTests.java b/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyAccessorTests.java index 0b7576bad4ca..c30a9139e656 100644 --- a/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyAccessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyAccessorTests.java @@ -43,18 +43,18 @@ import org.springframework.beans.propertyeditors.StringArrayPropertyEditor; import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.beans.support.DerivedFromProtectedBaseBean; +import org.springframework.beans.testfixture.beans.BooleanTestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.IndexedTestBean; +import org.springframework.beans.testfixture.beans.NumberTestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.GenericConversionService; +import org.springframework.core.testfixture.Assume; +import org.springframework.core.testfixture.EnabledForTestGroups; import org.springframework.lang.Nullable; -import org.springframework.tests.Assume; -import org.springframework.tests.EnabledForTestGroups; -import org.springframework.tests.sample.beans.BooleanTestBean; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.IndexedTestBean; -import org.springframework.tests.sample.beans.NumberTestBean; -import org.springframework.tests.sample.beans.TestBean; import org.springframework.util.StopWatch; import org.springframework.util.StringUtils; @@ -62,7 +62,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.within; -import static org.springframework.tests.TestGroup.PERFORMANCE; +import static org.springframework.core.testfixture.TestGroup.PERFORMANCE; /** * Shared tests for property accessors. @@ -300,7 +300,7 @@ public void setNestedPropertyPolymorphic() throws Exception { AbstractPropertyAccessor accessor = createAccessor(target); accessor.setPropertyValue("spouse", kerry); - accessor.setPropertyValue("spouse.age", new Integer(35)); + accessor.setPropertyValue("spouse.age", 35); accessor.setPropertyValue("spouse.name", "Kerry"); accessor.setPropertyValue("spouse.company", "Lewisham"); assertThat(kerry.getName().equals("Kerry")).as("kerry name is Kerry").isTrue(); @@ -389,7 +389,7 @@ public void setAnotherPropertyIntermediatePropertyIsNull() throws Exception { ITestBean target = new TestBean("rod", 31); AbstractPropertyAccessor accessor = createAccessor(target); assertThatExceptionOfType(NullValueInNestedPathException.class).isThrownBy(() -> - accessor.setPropertyValue("spouse.age", new Integer(31))) + accessor.setPropertyValue("spouse.age", 31)) .satisfies(ex -> assertThat(ex.getPropertyName()).isEqualTo("spouse")); } @@ -482,7 +482,7 @@ public void setIndividualValidPropertyValues() { int newAge = 65; String newTouchy = "valid"; AbstractPropertyAccessor accessor = createAccessor(target); - accessor.setPropertyValue("age", new Integer(newAge)); + accessor.setPropertyValue("age", newAge); accessor.setPropertyValue(new PropertyValue("name", newName)); accessor.setPropertyValue(new PropertyValue("touchy", newTouchy)); assertThat(target.getName().equals(newName)).as("Name property should have changed").isTrue(); @@ -618,13 +618,13 @@ public void setNumberProperties() { public void setNumberPropertiesWithCoercion() { NumberTestBean target = new NumberTestBean(); AbstractPropertyAccessor accessor = createAccessor(target); - accessor.setPropertyValue("short2", new Integer(2)); - accessor.setPropertyValue("int2", new Long(8)); + accessor.setPropertyValue("short2", 2); + accessor.setPropertyValue("int2", 8L); accessor.setPropertyValue("long2", new BigInteger("6")); - accessor.setPropertyValue("bigInteger", new Integer(3)); - accessor.setPropertyValue("float2", new Double(8.1)); + accessor.setPropertyValue("bigInteger", 3L); + accessor.setPropertyValue("float2", 8.1D); accessor.setPropertyValue("double2", new BigDecimal(6.1)); - accessor.setPropertyValue("bigDecimal", new Float(4.0)); + accessor.setPropertyValue("bigDecimal", 4.0F); assertThat(new Short("2").equals(accessor.getPropertyValue("short2"))).as("Correct short2 value").isTrue(); assertThat(new Short("2").equals(target.getShort2())).as("Correct short2 value").isTrue(); assertThat(new Integer("8").equals(accessor.getPropertyValue("int2"))).as("Correct int2 value").isTrue(); @@ -886,14 +886,14 @@ public void setIntArrayProperty() { result.add(target.intArray[0]); result.add(target.intArray[1]); result.add(target.intArray[2]); - assertThat(result.contains(new Integer(4)) && result.contains(new Integer(5)) && - result.contains(new Integer(3))).as("correct values").isTrue(); + assertThat(result.contains(4) && result.contains(5) && + result.contains(3)).as("correct values").isTrue(); accessor.setPropertyValue("intArray", new Integer[] {1}); assertThat(target.intArray.length == 1).as("intArray length = 4").isTrue(); assertThat(target.intArray[0] == 1).as("correct values").isTrue(); - accessor.setPropertyValue("intArray", new Integer(1)); + accessor.setPropertyValue("intArray", 1); assertThat(target.intArray.length == 1).as("intArray length = 4").isTrue(); assertThat(target.intArray[0] == 1).as("correct values").isTrue(); @@ -913,7 +913,7 @@ public void setIntArrayPropertyWithCustomEditor() { accessor.registerCustomEditor(int.class, new PropertyEditorSupport() { @Override public void setAsText(String text) { - setValue(new Integer(Integer.parseInt(text) + 1)); + setValue(Integer.parseInt(text) + 1); } }); @@ -927,7 +927,7 @@ public void setAsText(String text) { assertThat(target.intArray[0] == 4 && target.intArray[1] == 5 && target.intArray[2] == 2 && target.intArray[3] == 3).as("correct values").isTrue(); - accessor.setPropertyValue("intArray", new Integer(1)); + accessor.setPropertyValue("intArray", 1); assertThat(target.intArray.length == 1).as("intArray length = 4").isTrue(); assertThat(target.intArray[0] == 1).as("correct values").isTrue(); @@ -1022,7 +1022,7 @@ public void setPrimitiveArrayPropertyLargeMatchingWithSpecificEditor() { @Override public void setValue(Object value) { if (value instanceof Integer) { - super.setValue(new Integer((Integer) value + 1)); + super.setValue((Integer) value + 1); } } }); @@ -1041,7 +1041,7 @@ public void setPrimitiveArrayPropertyLargeMatchingWithIndexSpecificEditor() { @Override public void setValue(Object value) { if (value instanceof Integer) { - super.setValue(new Integer((Integer) value + 1)); + super.setValue((Integer) value + 1); } } }); @@ -1210,16 +1210,16 @@ public void setCollectionPropertyWithIntegerValue() { AbstractPropertyAccessor accessor = createAccessor(target); Collection coll = new HashSet<>(); coll.add(0); - accessor.setPropertyValue("collection", new Integer(0)); + accessor.setPropertyValue("collection", 0); List set = new LinkedList<>(); set.add(1); - accessor.setPropertyValue("set", new Integer(1)); + accessor.setPropertyValue("set", 1); List sortedSet = new ArrayList<>(); sortedSet.add(2); - accessor.setPropertyValue("sortedSet", new Integer(2)); + accessor.setPropertyValue("sortedSet", 2); Set list = new HashSet<>(); list.add(3); - accessor.setPropertyValue("list", new Integer(3)); + accessor.setPropertyValue("list", 3); assertThat(target.getCollection().size()).isEqualTo(1); assertThat(target.getCollection().containsAll(coll)).isTrue(); assertThat(target.getSet().size()).isEqualTo(1); diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java index 544d06750a92..78c6f8b4b211 100644 --- a/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java @@ -34,16 +34,17 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.beans.testfixture.beans.DerivedTestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceEditor; import org.springframework.lang.Nullable; -import org.springframework.tests.sample.beans.DerivedTestBean; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.SoftAssertions.assertSoftly; /** * Unit tests for {@link BeanUtils}. @@ -80,19 +81,49 @@ void testInstantiateClassWithOptionalNullableType() throws NoSuchMethodException } @Test // gh-22531 - void testInstantiateClassWithOptionalPrimitiveType() throws NoSuchMethodException { - Constructor ctor = BeanWithPrimitiveTypes.class.getDeclaredConstructor(int.class, boolean.class, String.class); - BeanWithPrimitiveTypes bean = BeanUtils.instantiateClass(ctor, null, null, "foo"); - assertThat(bean.getCounter()).isEqualTo(0); - assertThat(bean.isFlag()).isEqualTo(false); - assertThat(bean.getValue()).isEqualTo("foo"); + void instantiateClassWithFewerArgsThanParameters() throws NoSuchMethodException { + Constructor constructor = getBeanWithPrimitiveTypesConstructor(); + + assertThatExceptionOfType(BeanInstantiationException.class).isThrownBy(() -> + BeanUtils.instantiateClass(constructor, null, null, "foo")); } - @Test // gh-22531 - void testInstantiateClassWithMoreArgsThanParameters() throws NoSuchMethodException { - Constructor ctor = BeanWithPrimitiveTypes.class.getDeclaredConstructor(int.class, boolean.class, String.class); + @Test // gh-22531 + void instantiateClassWithMoreArgsThanParameters() throws NoSuchMethodException { + Constructor constructor = getBeanWithPrimitiveTypesConstructor(); + assertThatExceptionOfType(BeanInstantiationException.class).isThrownBy(() -> - BeanUtils.instantiateClass(ctor, null, null, "foo", null)); + BeanUtils.instantiateClass(constructor, null, null, null, null, null, null, null, null, "foo", null)); + } + + @Test // gh-22531, gh-27390 + void instantiateClassWithOptionalPrimitiveTypes() throws NoSuchMethodException { + Constructor constructor = getBeanWithPrimitiveTypesConstructor(); + + BeanWithPrimitiveTypes bean = BeanUtils.instantiateClass(constructor, null, null, null, null, null, null, null, null, "foo"); + + assertSoftly(softly -> { + softly.assertThat(bean.isFlag()).isFalse(); + softly.assertThat(bean.getByteCount()).isEqualTo((byte) 0); + softly.assertThat(bean.getShortCount()).isEqualTo((short) 0); + softly.assertThat(bean.getIntCount()).isEqualTo(0); + softly.assertThat(bean.getLongCount()).isEqualTo(0L); + softly.assertThat(bean.getFloatCount()).isEqualTo(0F); + softly.assertThat(bean.getDoubleCount()).isEqualTo(0D); + softly.assertThat(bean.getCharacter()).isEqualTo('\0'); + softly.assertThat(bean.getText()).isEqualTo("foo"); + }); + } + + private Constructor getBeanWithPrimitiveTypesConstructor() throws NoSuchMethodException { + return BeanWithPrimitiveTypes.class.getConstructor(boolean.class, byte.class, short.class, int.class, + long.class, float.class, double.class, char.class, String.class); + } + + @Test + void testInstantiatePrivateClassWithPrivateConstructor() throws NoSuchMethodException { + Constructor ctor = PrivateBeanWithPrivateConstructor.class.getDeclaredConstructor(); + BeanUtils.instantiateClass(ctor); } @Test @@ -529,29 +560,73 @@ public String getValue() { private static class BeanWithPrimitiveTypes { - private int counter; - private boolean flag; + private byte byteCount; + private short shortCount; + private int intCount; + private long longCount; + private float floatCount; + private double doubleCount; + private char character; + private String text; - private String value; @SuppressWarnings("unused") - public BeanWithPrimitiveTypes(int counter, boolean flag, String value) { - this.counter = counter; - this.flag = flag; - this.value = value; - } + public BeanWithPrimitiveTypes(boolean flag, byte byteCount, short shortCount, int intCount, long longCount, + float floatCount, double doubleCount, char character, String text) { - public int getCounter() { - return counter; + this.flag = flag; + this.byteCount = byteCount; + this.shortCount = shortCount; + this.intCount = intCount; + this.longCount = longCount; + this.floatCount = floatCount; + this.doubleCount = doubleCount; + this.character = character; + this.text = text; } public boolean isFlag() { return flag; } - public String getValue() { - return value; + public byte getByteCount() { + return byteCount; + } + + public short getShortCount() { + return shortCount; + } + + public int getIntCount() { + return intCount; + } + + public long getLongCount() { + return longCount; + } + + public float getFloatCount() { + return floatCount; + } + + public double getDoubleCount() { + return doubleCount; + } + + public char getCharacter() { + return character; + } + + public String getText() { + return text; + } + + } + + private static class PrivateBeanWithPrivateConstructor { + + private PrivateBeanWithPrivateConstructor() { } } diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperAutoGrowingTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperAutoGrowingTests.java index c17e2c7359b0..78524e632b0c 100644 --- a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperAutoGrowingTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperAutoGrowingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ /** * @author Keith Donald * @author Juergen Hoeller + * @author Sam Brannen */ public class BeanWrapperAutoGrowingTests { @@ -37,7 +38,7 @@ public class BeanWrapperAutoGrowingTests { @BeforeEach - public void setUp() { + public void setup() { wrapper.setAutoGrowNestedPaths(true); } @@ -66,11 +67,6 @@ public void getPropertyValueAutoGrowArray() { assertThat(bean.getArray()[0]).isInstanceOf(Bean.class); } - private void assertNotNull(Object propertyValue) { - assertThat(propertyValue).isNotNull(); - } - - @Test public void setPropertyValueAutoGrowArray() { wrapper.setPropertyValue("array[0].prop", "test"); @@ -93,12 +89,39 @@ public void getPropertyValueAutoGrowArrayBySeveralElements() { } @Test - public void getPropertyValueAutoGrowMultiDimensionalArray() { + public void getPropertyValueAutoGrow2dArray() { assertNotNull(wrapper.getPropertyValue("multiArray[0][0]")); assertThat(bean.getMultiArray()[0].length).isEqualTo(1); assertThat(bean.getMultiArray()[0][0]).isInstanceOf(Bean.class); } + @Test + public void getPropertyValueAutoGrow3dArray() { + assertNotNull(wrapper.getPropertyValue("threeDimensionalArray[1][2][3]")); + assertThat(bean.getThreeDimensionalArray()[1].length).isEqualTo(3); + assertThat(bean.getThreeDimensionalArray()[1][2][3]).isInstanceOf(Bean.class); + } + + @Test + public void setPropertyValueAutoGrow2dArray() { + Bean newBean = new Bean(); + newBean.setProp("enigma"); + wrapper.setPropertyValue("multiArray[2][3]", newBean); + assertThat(bean.getMultiArray()[2][3]) + .isInstanceOf(Bean.class) + .extracting(Bean::getProp).isEqualTo("enigma"); + } + + @Test + public void setPropertyValueAutoGrow3dArray() { + Bean newBean = new Bean(); + newBean.setProp("enigma"); + wrapper.setPropertyValue("threeDimensionalArray[2][3][4]", newBean); + assertThat(bean.getThreeDimensionalArray()[2][3][4]) + .isInstanceOf(Bean.class) + .extracting(Bean::getProp).isEqualTo("enigma"); + } + @Test public void getPropertyValueAutoGrowList() { assertNotNull(wrapper.getPropertyValue("list[0]")); @@ -131,7 +154,7 @@ public void getPropertyValueAutoGrowListBySeveralElements() { public void getPropertyValueAutoGrowListFailsAgainstLimit() { wrapper.setAutoGrowCollectionLimit(2); assertThatExceptionOfType(InvalidPropertyException.class).isThrownBy(() -> - assertNotNull(wrapper.getPropertyValue("list[4]"))) + wrapper.getPropertyValue("list[4]")) .withRootCauseInstanceOf(IndexOutOfBoundsException.class); } @@ -161,6 +184,11 @@ public void setNestedPropertyValueAutoGrowMap() { } + private static void assertNotNull(Object propertyValue) { + assertThat(propertyValue).isNotNull(); + } + + @SuppressWarnings("rawtypes") public static class Bean { @@ -174,6 +202,8 @@ public static class Bean { private Bean[][] multiArray; + private Bean[][][] threeDimensionalArray; + private List list; private List> multiList; @@ -214,6 +244,14 @@ public void setMultiArray(Bean[][] multiArray) { this.multiArray = multiArray; } + public Bean[][][] getThreeDimensionalArray() { + return threeDimensionalArray; + } + + public void setThreeDimensionalArray(Bean[][][] threeDimensionalArray) { + this.threeDimensionalArray = threeDimensionalArray; + } + public List getList() { return list; } diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperEnumTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperEnumTests.java index 5327e70a3a45..3a5ac3717127 100644 --- a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperEnumTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperEnumTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,9 @@ import org.junit.jupiter.api.Test; +import org.springframework.beans.testfixture.beans.CustomEnum; +import org.springframework.beans.testfixture.beans.GenericBean; import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.tests.sample.beans.CustomEnum; -import org.springframework.tests.sample.beans.GenericBean; import static org.assertj.core.api.Assertions.assertThat; @@ -158,8 +158,8 @@ public void testStandardEnumMapWithMultipleValues() { map.put("VALUE_2", 2); bw.setPropertyValue("standardEnumMap", map); assertThat(gb.getStandardEnumMap().size()).isEqualTo(2); - assertThat(gb.getStandardEnumMap().get(CustomEnum.VALUE_1)).isEqualTo(new Integer(1)); - assertThat(gb.getStandardEnumMap().get(CustomEnum.VALUE_2)).isEqualTo(new Integer(2)); + assertThat(gb.getStandardEnumMap().get(CustomEnum.VALUE_1)).isEqualTo(1); + assertThat(gb.getStandardEnumMap().get(CustomEnum.VALUE_2)).isEqualTo(2); } @Test @@ -170,7 +170,7 @@ public void testStandardEnumMapWithAutoGrowing() { assertThat(gb.getStandardEnumMap()).isNull(); bw.setPropertyValue("standardEnumMap[VALUE_1]", 1); assertThat(gb.getStandardEnumMap().size()).isEqualTo(1); - assertThat(gb.getStandardEnumMap().get(CustomEnum.VALUE_1)).isEqualTo(new Integer(1)); + assertThat(gb.getStandardEnumMap().get(CustomEnum.VALUE_1)).isEqualTo(1); } @Test diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperGenericsTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperGenericsTests.java index 9205b2c5f995..01dfc0674a56 100644 --- a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperGenericsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperGenericsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ package org.springframework.beans; -import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -33,11 +32,11 @@ import org.springframework.beans.propertyeditors.CustomNumberEditor; import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.beans.testfixture.beans.GenericBean; +import org.springframework.beans.testfixture.beans.GenericIntegerBean; +import org.springframework.beans.testfixture.beans.GenericSetOfIntegerBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.UrlResource; -import org.springframework.tests.sample.beans.GenericBean; -import org.springframework.tests.sample.beans.GenericIntegerBean; -import org.springframework.tests.sample.beans.GenericSetOfIntegerBean; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -57,8 +56,8 @@ public void testGenericSet() { input.add("4"); input.add("5"); bw.setPropertyValue("integerSet", input); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); } @Test @@ -70,8 +69,8 @@ public void testGenericLowerBoundedSet() { input.add("4"); input.add("5"); bw.setPropertyValue("numberSet", input); - assertThat(gb.getNumberSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getNumberSet().contains(new Integer(5))).isTrue(); + assertThat(gb.getNumberSet().contains(4)).isTrue(); + assertThat(gb.getNumberSet().contains(5)).isTrue(); } @Test @@ -86,7 +85,7 @@ public void testGenericSetWithConversionFailure() { } @Test - public void testGenericList() throws MalformedURLException { + public void testGenericList() throws Exception { GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); List input = new ArrayList<>(); @@ -98,7 +97,7 @@ public void testGenericList() throws MalformedURLException { } @Test - public void testGenericListElement() throws MalformedURLException { + public void testGenericListElement() throws Exception { GenericBean gb = new GenericBean<>(); gb.setResourceList(new ArrayList<>()); BeanWrapper bw = new BeanWrapperImpl(gb); @@ -114,8 +113,8 @@ public void testGenericMap() { input.put("4", "5"); input.put("6", "7"); bw.setPropertyValue("shortMap", input); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(new Integer(7)); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(7); } @Test @@ -124,8 +123,8 @@ public void testGenericMapElement() { gb.setShortMap(new HashMap<>()); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("shortMap[4]", "5"); - assertThat(bw.getPropertyValue("shortMap[4]")).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); + assertThat(bw.getPropertyValue("shortMap[4]")).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); } @Test @@ -136,8 +135,8 @@ public void testGenericMapWithKeyType() { input.put("4", "5"); input.put("6", "7"); bw.setPropertyValue("longMap", input); - assertThat(gb.getLongMap().get(new Long("4"))).isEqualTo("5"); - assertThat(gb.getLongMap().get(new Long("6"))).isEqualTo("7"); + assertThat(gb.getLongMap().get(4L)).isEqualTo("5"); + assertThat(gb.getLongMap().get(6L)).isEqualTo("7"); } @Test @@ -157,16 +156,14 @@ public void testGenericMapWithCollectionValue() { bw.registerCustomEditor(Number.class, new CustomNumberEditor(Integer.class, false)); Map> input = new HashMap<>(); HashSet value1 = new HashSet<>(); - value1.add(new Integer(1)); + value1.add(1); input.put("1", value1); ArrayList value2 = new ArrayList<>(); value2.add(Boolean.TRUE); input.put("2", value2); bw.setPropertyValue("collectionMap", input); - boolean condition1 = gb.getCollectionMap().get(new Integer(1)) instanceof HashSet; - assertThat(condition1).isTrue(); - boolean condition = gb.getCollectionMap().get(new Integer(2)) instanceof ArrayList; - assertThat(condition).isTrue(); + assertThat(gb.getCollectionMap().get(1) instanceof HashSet).isTrue(); + assertThat(gb.getCollectionMap().get(2) instanceof ArrayList).isTrue(); } @Test @@ -176,10 +173,9 @@ public void testGenericMapElementWithCollectionValue() { BeanWrapper bw = new BeanWrapperImpl(gb); bw.registerCustomEditor(Number.class, new CustomNumberEditor(Integer.class, false)); HashSet value1 = new HashSet<>(); - value1.add(new Integer(1)); + value1.add(1); bw.setPropertyValue("collectionMap[1]", value1); - boolean condition = gb.getCollectionMap().get(new Integer(1)) instanceof HashSet; - assertThat(condition).isTrue(); + assertThat(gb.getCollectionMap().get(1) instanceof HashSet).isTrue(); } @Test @@ -190,36 +186,36 @@ public void testGenericMapFromProperties() { input.setProperty("4", "5"); input.setProperty("6", "7"); bw.setPropertyValue("shortMap", input); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(new Integer(7)); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(7); } @Test - public void testGenericListOfLists() throws MalformedURLException { + public void testGenericListOfLists() { GenericBean gb = new GenericBean<>(); List> list = new LinkedList<>(); list.add(new LinkedList<>()); gb.setListOfLists(list); BeanWrapper bw = new BeanWrapperImpl(gb); - bw.setPropertyValue("listOfLists[0][0]", new Integer(5)); - assertThat(bw.getPropertyValue("listOfLists[0][0]")).isEqualTo(new Integer(5)); - assertThat(gb.getListOfLists().get(0).get(0)).isEqualTo(new Integer(5)); + bw.setPropertyValue("listOfLists[0][0]", 5); + assertThat(bw.getPropertyValue("listOfLists[0][0]")).isEqualTo(5); + assertThat(gb.getListOfLists().get(0).get(0)).isEqualTo(5); } @Test - public void testGenericListOfListsWithElementConversion() throws MalformedURLException { + public void testGenericListOfListsWithElementConversion() { GenericBean gb = new GenericBean<>(); List> list = new LinkedList<>(); list.add(new LinkedList<>()); gb.setListOfLists(list); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("listOfLists[0][0]", "5"); - assertThat(bw.getPropertyValue("listOfLists[0][0]")).isEqualTo(new Integer(5)); - assertThat(gb.getListOfLists().get(0).get(0)).isEqualTo(new Integer(5)); + assertThat(bw.getPropertyValue("listOfLists[0][0]")).isEqualTo(5); + assertThat(gb.getListOfLists().get(0).get(0)).isEqualTo(5); } @Test - public void testGenericListOfArrays() throws MalformedURLException { + public void testGenericListOfArrays() { GenericBean gb = new GenericBean<>(); ArrayList list = new ArrayList<>(); list.add(new String[] {"str1", "str2"}); @@ -231,7 +227,7 @@ public void testGenericListOfArrays() throws MalformedURLException { } @Test - public void testGenericListOfArraysWithElementConversion() throws MalformedURLException { + public void testGenericListOfArraysWithElementConversion() { GenericBean gb = new GenericBean<>(); ArrayList list = new ArrayList<>(); list.add(new String[] {"str1", "str2"}); @@ -244,7 +240,7 @@ public void testGenericListOfArraysWithElementConversion() throws MalformedURLEx } @Test - public void testGenericListOfMaps() throws MalformedURLException { + public void testGenericListOfMaps() { GenericBean gb = new GenericBean<>(); List> list = new LinkedList<>(); list.add(new HashMap<>()); @@ -256,7 +252,7 @@ public void testGenericListOfMaps() throws MalformedURLException { } @Test - public void testGenericListOfMapsWithElementConversion() throws MalformedURLException { + public void testGenericListOfMapsWithElementConversion() { GenericBean gb = new GenericBean<>(); List> list = new LinkedList<>(); list.add(new HashMap<>()); @@ -268,7 +264,7 @@ public void testGenericListOfMapsWithElementConversion() throws MalformedURLExce } @Test - public void testGenericMapOfMaps() throws MalformedURLException { + public void testGenericMapOfMaps() { GenericBean gb = new GenericBean<>(); Map> map = new HashMap<>(); map.put("mykey", new HashMap<>()); @@ -280,7 +276,7 @@ public void testGenericMapOfMaps() throws MalformedURLException { } @Test - public void testGenericMapOfMapsWithElementConversion() throws MalformedURLException { + public void testGenericMapOfMapsWithElementConversion() { GenericBean gb = new GenericBean<>(); Map> map = new HashMap<>(); map.put("mykey", new HashMap<>()); @@ -292,31 +288,31 @@ public void testGenericMapOfMapsWithElementConversion() throws MalformedURLExcep } @Test - public void testGenericMapOfLists() throws MalformedURLException { + public void testGenericMapOfLists() { GenericBean gb = new GenericBean<>(); Map> map = new HashMap<>(); - map.put(new Integer(1), new LinkedList<>()); + map.put(1, new LinkedList<>()); gb.setMapOfLists(map); BeanWrapper bw = new BeanWrapperImpl(gb); - bw.setPropertyValue("mapOfLists[1][0]", new Integer(5)); - assertThat(bw.getPropertyValue("mapOfLists[1][0]")).isEqualTo(new Integer(5)); - assertThat(gb.getMapOfLists().get(new Integer(1)).get(0)).isEqualTo(new Integer(5)); + bw.setPropertyValue("mapOfLists[1][0]", 5); + assertThat(bw.getPropertyValue("mapOfLists[1][0]")).isEqualTo(5); + assertThat(gb.getMapOfLists().get(1).get(0)).isEqualTo(5); } @Test - public void testGenericMapOfListsWithElementConversion() throws MalformedURLException { + public void testGenericMapOfListsWithElementConversion() { GenericBean gb = new GenericBean<>(); Map> map = new HashMap<>(); - map.put(new Integer(1), new LinkedList<>()); + map.put(1, new LinkedList<>()); gb.setMapOfLists(map); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("mapOfLists[1][0]", "5"); - assertThat(bw.getPropertyValue("mapOfLists[1][0]")).isEqualTo(new Integer(5)); - assertThat(gb.getMapOfLists().get(new Integer(1)).get(0)).isEqualTo(new Integer(5)); + assertThat(bw.getPropertyValue("mapOfLists[1][0]")).isEqualTo(5); + assertThat(gb.getMapOfLists().get(1).get(0)).isEqualTo(5); } @Test - public void testGenericTypeNestingMapOfInteger() throws Exception { + public void testGenericTypeNestingMapOfInteger() { Map map = new HashMap<>(); map.put("testKey", "100"); @@ -325,14 +321,13 @@ public void testGenericTypeNestingMapOfInteger() throws Exception { bw.setPropertyValue("mapOfInteger", map); Object obj = gb.getMapOfInteger().get("testKey"); - boolean condition = obj instanceof Integer; - assertThat(condition).isTrue(); + assertThat(obj instanceof Integer).isTrue(); } @Test - public void testGenericTypeNestingMapOfListOfInteger() throws Exception { + public void testGenericTypeNestingMapOfListOfInteger() { Map> map = new HashMap<>(); - List list = Arrays.asList(new String[] {"1", "2", "3"}); + List list = Arrays.asList("1", "2", "3"); map.put("testKey", list); NestedGenericCollectionBean gb = new NestedGenericCollectionBean(); @@ -340,13 +335,12 @@ public void testGenericTypeNestingMapOfListOfInteger() throws Exception { bw.setPropertyValue("mapOfListOfInteger", map); Object obj = gb.getMapOfListOfInteger().get("testKey").get(0); - boolean condition = obj instanceof Integer; - assertThat(condition).isTrue(); + assertThat(obj instanceof Integer).isTrue(); assertThat(((Integer) obj).intValue()).isEqualTo(1); } @Test - public void testGenericTypeNestingListOfMapOfInteger() throws Exception { + public void testGenericTypeNestingListOfMapOfInteger() { List> list = new LinkedList<>(); Map map = new HashMap<>(); map.put("testKey", "5"); @@ -357,15 +351,14 @@ public void testGenericTypeNestingListOfMapOfInteger() throws Exception { bw.setPropertyValue("listOfMapOfInteger", list); Object obj = gb.getListOfMapOfInteger().get(0).get("testKey"); - boolean condition = obj instanceof Integer; - assertThat(condition).isTrue(); + assertThat(obj instanceof Integer).isTrue(); assertThat(((Integer) obj).intValue()).isEqualTo(5); } @Test - public void testGenericTypeNestingMapOfListOfListOfInteger() throws Exception { + public void testGenericTypeNestingMapOfListOfListOfInteger() { Map>> map = new HashMap<>(); - List list = Arrays.asList(new String[] {"1", "2", "3"}); + List list = Arrays.asList("1", "2", "3"); map.put("testKey", Collections.singletonList(list)); NestedGenericCollectionBean gb = new NestedGenericCollectionBean(); @@ -373,8 +366,7 @@ public void testGenericTypeNestingMapOfListOfListOfInteger() throws Exception { bw.setPropertyValue("mapOfListOfListOfInteger", map); Object obj = gb.getMapOfListOfListOfInteger().get("testKey").get(0).get(0); - boolean condition = obj instanceof Integer; - assertThat(condition).isTrue(); + assertThat(obj instanceof Integer).isTrue(); assertThat(((Integer) obj).intValue()).isEqualTo(1); } @@ -391,7 +383,7 @@ public void testComplexGenericMap() { BeanWrapper bw = new BeanWrapperImpl(holder); bw.setPropertyValue("genericMap", inputMap); - assertThat(holder.getGenericMap().keySet().iterator().next().get(0)).isEqualTo(new Integer(1)); + assertThat(holder.getGenericMap().keySet().iterator().next().get(0)).isEqualTo(1); assertThat(holder.getGenericMap().values().iterator().next().get(0)).isEqualTo(new Long(10)); } @@ -408,7 +400,7 @@ public void testComplexGenericMapWithCollectionConversion() { BeanWrapper bw = new BeanWrapperImpl(holder); bw.setPropertyValue("genericMap", inputMap); - assertThat(holder.getGenericMap().keySet().iterator().next().get(0)).isEqualTo(new Integer(1)); + assertThat(holder.getGenericMap().keySet().iterator().next().get(0)).isEqualTo(1); assertThat(holder.getGenericMap().values().iterator().next().get(0)).isEqualTo(new Long(10)); } @@ -421,7 +413,7 @@ public void testComplexGenericIndexedMapEntry() { BeanWrapper bw = new BeanWrapperImpl(holder); bw.setPropertyValue("genericIndexedMap[1]", inputValue); - assertThat(holder.getGenericIndexedMap().keySet().iterator().next()).isEqualTo(new Integer(1)); + assertThat(holder.getGenericIndexedMap().keySet().iterator().next()).isEqualTo(1); assertThat(holder.getGenericIndexedMap().values().iterator().next().get(0)).isEqualTo(new Long(10)); } @@ -434,7 +426,7 @@ public void testComplexGenericIndexedMapEntryWithCollectionConversion() { BeanWrapper bw = new BeanWrapperImpl(holder); bw.setPropertyValue("genericIndexedMap[1]", inputValue); - assertThat(holder.getGenericIndexedMap().keySet().iterator().next()).isEqualTo(new Integer(1)); + assertThat(holder.getGenericIndexedMap().keySet().iterator().next()).isEqualTo(1); assertThat(holder.getGenericIndexedMap().values().iterator().next().get(0)).isEqualTo(new Long(10)); } @@ -447,7 +439,7 @@ public void testComplexDerivedIndexedMapEntry() { BeanWrapper bw = new BeanWrapperImpl(holder); bw.setPropertyValue("derivedIndexedMap[1]", inputValue); - assertThat(holder.getDerivedIndexedMap().keySet().iterator().next()).isEqualTo(new Integer(1)); + assertThat(holder.getDerivedIndexedMap().keySet().iterator().next()).isEqualTo(1); assertThat(holder.getDerivedIndexedMap().values().iterator().next().get(0)).isEqualTo(new Long(10)); } @@ -460,30 +452,30 @@ public void testComplexDerivedIndexedMapEntryWithCollectionConversion() { BeanWrapper bw = new BeanWrapperImpl(holder); bw.setPropertyValue("derivedIndexedMap[1]", inputValue); - assertThat(holder.getDerivedIndexedMap().keySet().iterator().next()).isEqualTo(new Integer(1)); + assertThat(holder.getDerivedIndexedMap().keySet().iterator().next()).isEqualTo(1); assertThat(holder.getDerivedIndexedMap().values().iterator().next().get(0)).isEqualTo(new Long(10)); } @Test - public void testGenericallyTypedIntegerBean() throws Exception { + public void testGenericallyTypedIntegerBean() { GenericIntegerBean gb = new GenericIntegerBean(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("genericProperty", "10"); bw.setPropertyValue("genericListProperty", new String[] {"20", "30"}); - assertThat(gb.getGenericProperty()).isEqualTo(new Integer(10)); - assertThat(gb.getGenericListProperty().get(0)).isEqualTo(new Integer(20)); - assertThat(gb.getGenericListProperty().get(1)).isEqualTo(new Integer(30)); + assertThat(gb.getGenericProperty()).isEqualTo(10); + assertThat(gb.getGenericListProperty().get(0)).isEqualTo(20); + assertThat(gb.getGenericListProperty().get(1)).isEqualTo(30); } @Test - public void testGenericallyTypedSetOfIntegerBean() throws Exception { + public void testGenericallyTypedSetOfIntegerBean() { GenericSetOfIntegerBean gb = new GenericSetOfIntegerBean(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("genericProperty", "10"); bw.setPropertyValue("genericListProperty", new String[] {"20", "30"}); - assertThat(gb.getGenericProperty().iterator().next()).isEqualTo(new Integer(10)); - assertThat(gb.getGenericListProperty().get(0).iterator().next()).isEqualTo(new Integer(20)); - assertThat(gb.getGenericListProperty().get(1).iterator().next()).isEqualTo(new Integer(30)); + assertThat(gb.getGenericProperty().iterator().next()).isEqualTo(10); + assertThat(gb.getGenericListProperty().get(0).iterator().next()).isEqualTo(20); + assertThat(gb.getGenericListProperty().get(1).iterator().next()).isEqualTo(30); } @Test diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java index a46b1957d994..0711189b5f59 100644 --- a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java @@ -22,7 +22,7 @@ import org.junit.jupiter.api.Test; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-beans/src/test/java/org/springframework/beans/CachedIntrospectionResultsTests.java b/spring-beans/src/test/java/org/springframework/beans/CachedIntrospectionResultsTests.java index 4c867e3b69ef..cba7e4964a98 100644 --- a/spring-beans/src/test/java/org/springframework/beans/CachedIntrospectionResultsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/CachedIntrospectionResultsTests.java @@ -22,8 +22,8 @@ import org.junit.jupiter.api.Test; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.OverridingClassLoader; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; @@ -42,7 +42,7 @@ public void acceptAndClearClassLoader() throws Exception { assertThat(CachedIntrospectionResults.strongClassCache.containsKey(TestBean.class)).isTrue(); ClassLoader child = new OverridingClassLoader(getClass().getClassLoader()); - Class tbClass = child.loadClass("org.springframework.tests.sample.beans.TestBean"); + Class tbClass = child.loadClass("org.springframework.beans.testfixture.beans.TestBean"); assertThat(CachedIntrospectionResults.strongClassCache.containsKey(tbClass)).isFalse(); CachedIntrospectionResults.acceptClassLoader(child); bw = new BeanWrapperImpl(tbClass); diff --git a/spring-beans/src/test/java/org/springframework/beans/DirectFieldAccessorTests.java b/spring-beans/src/test/java/org/springframework/beans/DirectFieldAccessorTests.java index de10f1a982b6..1ca8ddc60298 100644 --- a/spring-beans/src/test/java/org/springframework/beans/DirectFieldAccessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/DirectFieldAccessorTests.java @@ -18,7 +18,7 @@ import org.junit.jupiter.api.Test; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java b/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java index 640b1b920fb9..d9876729023f 100644 --- a/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java index 47aa95f8a929..e869c9c6c906 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package org.springframework.beans.factory; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -26,23 +28,25 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.StaticListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.testfixture.beans.AnnotatedBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.IndexedTestBean; +import org.springframework.beans.testfixture.beans.TestAnnotation; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.beans.testfixture.beans.factory.DummyFactory; import org.springframework.cglib.proxy.NoOp; +import org.springframework.core.annotation.AliasFor; import org.springframework.core.io.Resource; -import org.springframework.tests.sample.beans.AnnotatedBean; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.IndexedTestBean; -import org.springframework.tests.sample.beans.TestAnnotation; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.tests.sample.beans.factory.DummyFactory; import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Rod Johnson * @author Juergen Hoeller * @author Chris Beams + * @author Sam Brannen * @since 04.07.2003 */ public class BeanFactoryUtilsTests { @@ -59,9 +63,8 @@ public class BeanFactoryUtilsTests { @BeforeEach - public void setUp() { + public void setup() { // Interesting hierarchical factory to test counts. - // Slow to read so we cache it. DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory(); new XmlBeanDefinitionReader(grandParent).loadBeanDefinitions(ROOT_CONTEXT); @@ -89,7 +92,7 @@ public void testHierarchicalCountBeansWithNonHierarchicalFactory() { * Check that override doesn't count as two separate beans. */ @Test - public void testHierarchicalCountBeansWithOverride() throws Exception { + public void testHierarchicalCountBeansWithOverride() { // Leaf count assertThat(this.listableBeanFactory.getBeanDefinitionCount() == 1).isTrue(); // Count minus duplicate @@ -97,14 +100,14 @@ public void testHierarchicalCountBeansWithOverride() throws Exception { } @Test - public void testHierarchicalNamesWithNoMatch() throws Exception { + public void testHierarchicalNamesWithNoMatch() { List names = Arrays.asList( BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class)); assertThat(names.size()).isEqualTo(0); } @Test - public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception { + public void testHierarchicalNamesWithMatchOnlyInRoot() { List names = Arrays.asList( BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class)); assertThat(names.size()).isEqualTo(1); @@ -114,7 +117,7 @@ public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception { } @Test - public void testGetBeanNamesForTypeWithOverride() throws Exception { + public void testGetBeanNamesForTypeWithOverride() { List names = Arrays.asList( BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class)); // includes 2 TestBeans from FactoryBeans (DummyFactory definitions) @@ -232,7 +235,7 @@ public void testFindsBeansOfTypeWithDefaultFactory() { } @Test - public void testHierarchicalResolutionWithOverride() throws Exception { + public void testHierarchicalResolutionWithOverride() { Object test3 = this.listableBeanFactory.getBean("test3"); Object test = this.listableBeanFactory.getBean("test"); @@ -272,14 +275,14 @@ public void testHierarchicalResolutionWithOverride() throws Exception { } @Test - public void testHierarchicalNamesForAnnotationWithNoMatch() throws Exception { + public void testHierarchicalNamesForAnnotationWithNoMatch() { List names = Arrays.asList( BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, Override.class)); assertThat(names.size()).isEqualTo(0); } @Test - public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() throws Exception { + public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() { List names = Arrays.asList( BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, TestAnnotation.class)); assertThat(names.size()).isEqualTo(1); @@ -289,7 +292,7 @@ public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() throws Excep } @Test - public void testGetBeanNamesForAnnotationWithOverride() throws Exception { + public void testGetBeanNamesForAnnotationWithOverride() { AnnotatedBean annotatedBean = new AnnotatedBean(); this.listableBeanFactory.registerSingleton("anotherAnnotatedBean", annotatedBean); List names = Arrays.asList( @@ -323,4 +326,168 @@ public void testIntDependencies() { assertThat(Arrays.equals(new String[] { "buffer" }, deps)).isTrue(); } + @Test + public void findAnnotationOnBean() { + this.listableBeanFactory.registerSingleton("controllerAdvice", new ControllerAdviceClass()); + this.listableBeanFactory.registerSingleton("restControllerAdvice", new RestControllerAdviceClass()); + testFindAnnotationOnBean(this.listableBeanFactory); + } + + @Test // gh-25520 + public void findAnnotationOnBeanWithStaticFactory() { + StaticListableBeanFactory lbf = new StaticListableBeanFactory(); + lbf.addBean("controllerAdvice", new ControllerAdviceClass()); + lbf.addBean("restControllerAdvice", new RestControllerAdviceClass()); + testFindAnnotationOnBean(lbf); + } + + private void testFindAnnotationOnBean(ListableBeanFactory lbf) { + assertControllerAdvice(lbf, "controllerAdvice"); + assertControllerAdvice(lbf, "restControllerAdvice"); + } + + private void assertControllerAdvice(ListableBeanFactory lbf, String beanName) { + ControllerAdvice controllerAdvice = lbf.findAnnotationOnBean(beanName, ControllerAdvice.class); + assertThat(controllerAdvice).isNotNull(); + assertThat(controllerAdvice.value()).isEqualTo("com.example"); + assertThat(controllerAdvice.basePackage()).isEqualTo("com.example"); + } + + @Test + public void isSingletonAndIsPrototypeWithStaticFactory() { + StaticListableBeanFactory lbf = new StaticListableBeanFactory(); + TestBean bean = new TestBean(); + DummyFactory fb1 = new DummyFactory(); + DummyFactory fb2 = new DummyFactory(); + fb2.setSingleton(false); + TestBeanSmartFactoryBean sfb1 = new TestBeanSmartFactoryBean(true, true); + TestBeanSmartFactoryBean sfb2 = new TestBeanSmartFactoryBean(true, false); + TestBeanSmartFactoryBean sfb3 = new TestBeanSmartFactoryBean(false, true); + TestBeanSmartFactoryBean sfb4 = new TestBeanSmartFactoryBean(false, false); + lbf.addBean("bean", bean); + lbf.addBean("fb1", fb1); + lbf.addBean("fb2", fb2); + lbf.addBean("sfb1", sfb1); + lbf.addBean("sfb2", sfb2); + lbf.addBean("sfb3", sfb3); + lbf.addBean("sfb4", sfb4); + + Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, true); + assertThat(beans.get("bean")).isSameAs(bean); + assertThat(beans.get("fb1")).isSameAs(fb1.getObject()); + assertThat(beans.get("fb2")).isInstanceOf(TestBean.class); + assertThat(beans.get("sfb1")).isInstanceOf(TestBean.class); + assertThat(beans.get("sfb2")).isInstanceOf(TestBean.class); + assertThat(beans.get("sfb3")).isInstanceOf(TestBean.class); + assertThat(beans.get("sfb4")).isInstanceOf(TestBean.class); + + assertThat(lbf.getBeanDefinitionCount()).isEqualTo(7); + assertThat(lbf.getBean("bean")).isInstanceOf(TestBean.class); + assertThat(lbf.getBean("&fb1")).isInstanceOf(FactoryBean.class); + assertThat(lbf.getBean("&fb2")).isInstanceOf(FactoryBean.class); + assertThat(lbf.getBean("&sfb1")).isInstanceOf(SmartFactoryBean.class); + assertThat(lbf.getBean("&sfb2")).isInstanceOf(SmartFactoryBean.class); + assertThat(lbf.getBean("&sfb3")).isInstanceOf(SmartFactoryBean.class); + assertThat(lbf.getBean("&sfb4")).isInstanceOf(SmartFactoryBean.class); + + assertThat(lbf.isSingleton("bean")).isTrue(); + assertThat(lbf.isSingleton("fb1")).isTrue(); + assertThat(lbf.isSingleton("fb2")).isTrue(); + assertThat(lbf.isSingleton("sfb1")).isTrue(); + assertThat(lbf.isSingleton("sfb2")).isTrue(); + assertThat(lbf.isSingleton("sfb3")).isTrue(); + assertThat(lbf.isSingleton("sfb4")).isTrue(); + + assertThat(lbf.isSingleton("&fb1")).isTrue(); + assertThat(lbf.isSingleton("&fb2")).isFalse(); + assertThat(lbf.isSingleton("&sfb1")).isTrue(); + assertThat(lbf.isSingleton("&sfb2")).isTrue(); + assertThat(lbf.isSingleton("&sfb3")).isFalse(); + assertThat(lbf.isSingleton("&sfb4")).isFalse(); + + assertThat(lbf.isPrototype("bean")).isFalse(); + assertThat(lbf.isPrototype("fb1")).isFalse(); + assertThat(lbf.isPrototype("fb2")).isFalse(); + assertThat(lbf.isPrototype("sfb1")).isFalse(); + assertThat(lbf.isPrototype("sfb2")).isFalse(); + assertThat(lbf.isPrototype("sfb3")).isFalse(); + assertThat(lbf.isPrototype("sfb4")).isFalse(); + + assertThat(lbf.isPrototype("&fb1")).isFalse(); + assertThat(lbf.isPrototype("&fb2")).isTrue(); + assertThat(lbf.isPrototype("&sfb1")).isTrue(); + assertThat(lbf.isPrototype("&sfb2")).isFalse(); + assertThat(lbf.isPrototype("&sfb3")).isTrue(); + assertThat(lbf.isPrototype("&sfb4")).isTrue(); + } + + + @Retention(RetentionPolicy.RUNTIME) + @interface ControllerAdvice { + + @AliasFor("basePackage") + String value() default ""; + + @AliasFor("value") + String basePackage() default ""; + } + + + @Retention(RetentionPolicy.RUNTIME) + @ControllerAdvice + @interface RestControllerAdvice { + + @AliasFor(annotation = ControllerAdvice.class) + String value() default ""; + + @AliasFor(annotation = ControllerAdvice.class) + String basePackage() default ""; + } + + + @ControllerAdvice("com.example") + static class ControllerAdviceClass { + } + + + @RestControllerAdvice("com.example") + static class RestControllerAdviceClass { + } + + + static class TestBeanSmartFactoryBean implements SmartFactoryBean { + + private final TestBean testBean = new TestBean("enigma", 42); + + private final boolean singleton; + + private final boolean prototype; + + TestBeanSmartFactoryBean(boolean singleton, boolean prototype) { + this.singleton = singleton; + this.prototype = prototype; + } + + @Override + public boolean isSingleton() { + return this.singleton; + } + + @Override + public boolean isPrototype() { + return this.prototype; + } + + @Override + public Class getObjectType() { + return TestBean.class; + } + + public TestBean getObject() { + // We don't really care if the actual instance is a singleton or prototype + // for the tests that use this factory. + return this.testBean; + } + } + } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/ConcurrentBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/ConcurrentBeanFactoryTests.java index 87f7e0089a35..2e4857b4ccd1 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/ConcurrentBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/ConcurrentBeanFactoryTests.java @@ -33,11 +33,11 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.beans.propertyeditors.CustomDateEditor; -import org.springframework.tests.EnabledForTestGroups; -import org.springframework.tests.TestGroup; +import org.springframework.core.testfixture.EnabledForTestGroups; +import org.springframework.core.testfixture.TestGroup; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Guillaume Poirier diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java index b10dd72eba69..b4aac030245d 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,7 +62,6 @@ import org.springframework.beans.factory.config.BeanExpressionContext; import org.springframework.beans.factory.config.BeanExpressionResolver; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; import org.springframework.beans.factory.config.PropertiesFactoryBean; @@ -79,6 +78,14 @@ import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ConstructorDependenciesBean; import org.springframework.beans.propertyeditors.CustomNumberEditor; +import org.springframework.beans.testfixture.beans.DependenciesBean; +import org.springframework.beans.testfixture.beans.DerivedTestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.LifecycleBean; +import org.springframework.beans.testfixture.beans.NestedTestBean; +import org.springframework.beans.testfixture.beans.SideEffectBean; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.beans.testfixture.beans.factory.DummyFactory; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationAwareOrderComparator; @@ -87,19 +94,12 @@ import org.springframework.core.convert.support.GenericConversionService; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; +import org.springframework.core.testfixture.Assume; +import org.springframework.core.testfixture.EnabledForTestGroups; +import org.springframework.core.testfixture.TestGroup; +import org.springframework.core.testfixture.io.SerializationTestUtils; +import org.springframework.core.testfixture.security.TestPrincipal; import org.springframework.lang.Nullable; -import org.springframework.tests.Assume; -import org.springframework.tests.EnabledForTestGroups; -import org.springframework.tests.TestGroup; -import org.springframework.tests.sample.beans.DependenciesBean; -import org.springframework.tests.sample.beans.DerivedTestBean; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.LifecycleBean; -import org.springframework.tests.sample.beans.NestedTestBean; -import org.springframework.tests.sample.beans.SideEffectBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.tests.sample.beans.factory.DummyFactory; -import org.springframework.util.SerializationTestUtils; import org.springframework.util.StopWatch; import org.springframework.util.StringValueResolver; @@ -367,7 +367,7 @@ void staticFactoryMethodFoundByNonEagerTypeMatching() { @Test void staticPrototypeFactoryMethodFoundByNonEagerTypeMatching() { RootBeanDefinition rbd = new RootBeanDefinition(TestBeanFactory.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); rbd.setFactoryMethodName("createTestBean"); lbf.registerBeanDefinition("x1", rbd); @@ -423,7 +423,7 @@ void nonStaticPrototypeFactoryMethodFoundByNonEagerTypeMatching() { RootBeanDefinition rbd = new RootBeanDefinition(); rbd.setFactoryBeanName("factory"); rbd.setFactoryMethodName("createTestBeanNonStatic"); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); lbf.registerBeanDefinition("x1", rbd); TestBeanFactory.initialized = false; @@ -796,12 +796,13 @@ void canReferenceParentBeanFromChildViaAlias() { factory.registerBeanDefinition("child", childDefinition); factory.registerAlias("parent", "alias"); - TestBean child = (TestBean) factory.getBean("child"); + TestBean child = factory.getBean("child", TestBean.class); assertThat(child.getName()).isEqualTo(EXPECTED_NAME); assertThat(child.getAge()).isEqualTo(EXPECTED_AGE); - Object mergedBeanDefinition2 = factory.getMergedBeanDefinition("child"); + BeanDefinition mergedBeanDefinition1 = factory.getMergedBeanDefinition("child"); + BeanDefinition mergedBeanDefinition2 = factory.getMergedBeanDefinition("child"); - assertThat(mergedBeanDefinition2).as("Use cached merged bean definition").isEqualTo(mergedBeanDefinition2); + assertThat(mergedBeanDefinition1).as("Use cached merged bean definition").isSameAs(mergedBeanDefinition2); } @Test @@ -1181,11 +1182,11 @@ void registerExistingSingletonWithAlreadyBound() { @Test void reregisterBeanDefinition() { RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class); - bd1.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd1.setScope(BeanDefinition.SCOPE_PROTOTYPE); lbf.registerBeanDefinition("testBean", bd1); assertThat(lbf.getBean("testBean")).isInstanceOf(TestBean.class); RootBeanDefinition bd2 = new RootBeanDefinition(NestedTestBean.class); - bd2.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd2.setScope(BeanDefinition.SCOPE_PROTOTYPE); lbf.registerBeanDefinition("testBean", bd2); assertThat(lbf.getBean("testBean")).isInstanceOf(NestedTestBean.class); } @@ -1216,16 +1217,16 @@ void arrayPropertyWithOptionalAutowiring() throws MalformedURLException { @Test void arrayConstructorWithAutowiring() { - lbf.registerSingleton("integer1", new Integer(4)); - lbf.registerSingleton("integer2", new Integer(5)); + lbf.registerSingleton("integer1",4); + lbf.registerSingleton("integer2", 5); RootBeanDefinition rbd = new RootBeanDefinition(ArrayBean.class); rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); lbf.registerBeanDefinition("arrayBean", rbd); ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean"); - assertThat(ab.getIntegerArray()[0]).isEqualTo(new Integer(4)); - assertThat(ab.getIntegerArray()[1]).isEqualTo(new Integer(5)); + assertThat(ab.getIntegerArray()[0]).isEqualTo(4); + assertThat(ab.getIntegerArray()[1]).isEqualTo(5); } @Test @@ -1240,8 +1241,8 @@ void arrayConstructorWithOptionalAutowiring() { @Test void doubleArrayConstructorWithAutowiring() throws MalformedURLException { - lbf.registerSingleton("integer1", new Integer(4)); - lbf.registerSingleton("integer2", new Integer(5)); + lbf.registerSingleton("integer1", 4); + lbf.registerSingleton("integer2", 5); lbf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); lbf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); @@ -1250,8 +1251,8 @@ void doubleArrayConstructorWithAutowiring() throws MalformedURLException { lbf.registerBeanDefinition("arrayBean", rbd); ArrayBean ab = (ArrayBean) lbf.getBean("arrayBean"); - assertThat(ab.getIntegerArray()[0]).isEqualTo(new Integer(4)); - assertThat(ab.getIntegerArray()[1]).isEqualTo(new Integer(5)); + assertThat(ab.getIntegerArray()[0]).isEqualTo(4); + assertThat(ab.getIntegerArray()[1]).isEqualTo(5); assertThat(ab.getResourceArray()[0]).isEqualTo(new UrlResource("http://localhost:8080")); assertThat(ab.getResourceArray()[1]).isEqualTo(new UrlResource("http://localhost:9090")); } @@ -1430,6 +1431,29 @@ void getBeanByTypeWithNoneFound() { lbf.getBean(TestBean.class)); } + @Test + void getBeanByTypeWithLateRegistration() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> + lbf.getBean(TestBean.class)); + RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class); + lbf.registerBeanDefinition("bd1", bd1); + TestBean bean = lbf.getBean(TestBean.class); + assertThat(bean.getBeanName()).isEqualTo("bd1"); + } + + @Test + void getBeanByTypeWithLateRegistrationAgainstFrozen() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + lbf.freezeConfiguration(); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> + lbf.getBean(TestBean.class)); + RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class); + lbf.registerBeanDefinition("bd1", bd1); + TestBean bean = lbf.getBean(TestBean.class); + assertThat(bean.getBeanName()).isEqualTo("bd1"); + } + @Test void getBeanByTypeDefinedInParent() { DefaultListableBeanFactory parent = new DefaultListableBeanFactory(); @@ -1642,7 +1666,7 @@ void getBeanByTypeInstanceDefinedInParent() { void getBeanByTypeInstanceWithAmbiguity() { RootBeanDefinition bd1 = createConstructorDependencyBeanDefinition(99); RootBeanDefinition bd2 = new RootBeanDefinition(ConstructorDependency.class); - bd2.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd2.setScope(BeanDefinition.SCOPE_PROTOTYPE); bd2.getConstructorArgumentValues().addGenericArgumentValue("43"); lbf.registerBeanDefinition("bd1", bd1); lbf.registerBeanDefinition("bd2", bd2); @@ -1777,10 +1801,10 @@ void beanProviderSerialization() throws Exception { @Test void getBeanWithArgsNotCreatedForFactoryBeanChecking() { RootBeanDefinition bd1 = new RootBeanDefinition(ConstructorDependency.class); - bd1.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd1.setScope(BeanDefinition.SCOPE_PROTOTYPE); lbf.registerBeanDefinition("bd1", bd1); RootBeanDefinition bd2 = new RootBeanDefinition(ConstructorDependencyFactoryBean.class); - bd2.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd2.setScope(BeanDefinition.SCOPE_PROTOTYPE); lbf.registerBeanDefinition("bd2", bd2); ConstructorDependency bean = lbf.getBean(ConstructorDependency.class, 42); @@ -1797,7 +1821,7 @@ void getBeanWithArgsNotCreatedForFactoryBeanChecking() { private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) { RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependency.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bd.getConstructorArgumentValues().addGenericArgumentValue(age); return bd; } @@ -1826,8 +1850,7 @@ void autowireBeanWithFactoryBeanByType() { assertThat(factoryBean).as("The FactoryBean should have been registered.").isNotNull(); FactoryBeanDependentBean bean = (FactoryBeanDependentBean) lbf.autowire(FactoryBeanDependentBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); - Object mergedBeanDefinition2 = bean.getFactoryBean(); - assertThat(mergedBeanDefinition2).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(mergedBeanDefinition2); + assertThat(bean.getFactoryBean()).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(factoryBean); } @Test @@ -2283,7 +2306,7 @@ void prototypeFactoryBeanNotEagerlyCalledInCaseOfBeanClassName() { @Test void prototypeStringCreatedRepeatedly() { RootBeanDefinition stringDef = new RootBeanDefinition(String.class); - stringDef.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + stringDef.setScope(BeanDefinition.SCOPE_PROTOTYPE); stringDef.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue("value")); lbf.registerBeanDefinition("string", stringDef); String val1 = lbf.getBean("string", String.class); @@ -2299,7 +2322,7 @@ void prototypeWithArrayConversionForConstructor() { list.add("myName"); list.add("myBeanName"); RootBeanDefinition bd = new RootBeanDefinition(DerivedTestBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bd.getConstructorArgumentValues().addGenericArgumentValue(list); lbf.registerBeanDefinition("test", bd); DerivedTestBean tb = (DerivedTestBean) lbf.getBean("test"); @@ -2317,7 +2340,7 @@ void prototypeWithArrayConversionForFactoryMethod() { list.add("myName"); list.add("myBeanName"); RootBeanDefinition bd = new RootBeanDefinition(DerivedTestBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bd.setFactoryMethodName("create"); bd.getConstructorArgumentValues().addGenericArgumentValue(list); lbf.registerBeanDefinition("test", bd); @@ -2335,7 +2358,7 @@ void prototypeWithArrayConversionForFactoryMethod() { void prototypeCreationIsFastEnough() { Assume.notLogging(factoryLog); RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); lbf.registerBeanDefinition("test", rbd); lbf.freezeConfiguration(); StopWatch sw = new StopWatch(); @@ -2353,7 +2376,7 @@ void prototypeCreationIsFastEnough() { void prototypeCreationWithDependencyCheckIsFastEnough() { Assume.notLogging(factoryLog); RootBeanDefinition rbd = new RootBeanDefinition(LifecycleBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); rbd.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS); lbf.registerBeanDefinition("test", rbd); lbf.addBeanPostProcessor(new LifecycleBean.PostProcessor()); @@ -2373,7 +2396,7 @@ void prototypeCreationWithDependencyCheckIsFastEnough() { void prototypeCreationWithConstructorArgumentsIsFastEnough() { Assume.notLogging(factoryLog); RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); rbd.getConstructorArgumentValues().addGenericArgumentValue("juergen"); rbd.getConstructorArgumentValues().addGenericArgumentValue("99"); lbf.registerBeanDefinition("test", rbd); @@ -2394,7 +2417,7 @@ void prototypeCreationWithConstructorArgumentsIsFastEnough() { void prototypeCreationWithResolvedConstructorArgumentsIsFastEnough() { Assume.notLogging(factoryLog); RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); rbd.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("spouse")); lbf.registerBeanDefinition("test", rbd); lbf.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); @@ -2416,7 +2439,7 @@ void prototypeCreationWithResolvedConstructorArgumentsIsFastEnough() { void prototypeCreationWithPropertiesIsFastEnough() { Assume.notLogging(factoryLog); RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); rbd.getPropertyValues().add("name", "juergen"); rbd.getPropertyValues().add("age", "99"); lbf.registerBeanDefinition("test", rbd); @@ -2438,7 +2461,7 @@ void prototypeCreationWithPropertiesIsFastEnough() { void prototypeCreationWithResolvedPropertiesIsFastEnough() { Assume.notLogging(factoryLog); RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse")); lbf.registerBeanDefinition("test", rbd); lbf.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); @@ -2533,8 +2556,7 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) { BeanWithDestroyMethod.closeCount = 0; lbf.preInstantiateSingletons(); lbf.destroySingletons(); - Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount; - assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2); + assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1); } @Test @@ -2548,14 +2570,13 @@ void destroyMethodOnInnerBean() { BeanWithDestroyMethod.closeCount = 0; lbf.preInstantiateSingletons(); lbf.destroySingletons(); - Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount; - assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2); + assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(2); } @Test void destroyMethodOnInnerBeanAsPrototype() { RootBeanDefinition innerBd = new RootBeanDefinition(BeanWithDestroyMethod.class); - innerBd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + innerBd.setScope(BeanDefinition.SCOPE_PROTOTYPE); innerBd.setDestroyMethodName("close"); RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class); bd.setDestroyMethodName("close"); @@ -2564,8 +2585,7 @@ void destroyMethodOnInnerBeanAsPrototype() { BeanWithDestroyMethod.closeCount = 0; lbf.preInstantiateSingletons(); lbf.destroySingletons(); - Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount; - assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2); + assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1); } @Test @@ -2599,7 +2619,7 @@ private void findTypeOfPrototypeFactoryMethodOnBeanInstance(boolean singleton) { factoryMethodDefinitionWithProperties.setFactoryBeanName("factoryBeanInstance"); factoryMethodDefinitionWithProperties.setFactoryMethodName("create"); if (!singleton) { - factoryMethodDefinitionWithProperties.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + factoryMethodDefinitionWithProperties.setScope(BeanDefinition.SCOPE_PROTOTYPE); } lbf.registerBeanDefinition("fmWithProperties", factoryMethodDefinitionWithProperties); @@ -2607,7 +2627,7 @@ private void findTypeOfPrototypeFactoryMethodOnBeanInstance(boolean singleton) { factoryMethodDefinitionGeneric.setFactoryBeanName("factoryBeanInstance"); factoryMethodDefinitionGeneric.setFactoryMethodName("createGeneric"); if (!singleton) { - factoryMethodDefinitionGeneric.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + factoryMethodDefinitionGeneric.setScope(BeanDefinition.SCOPE_PROTOTYPE); } lbf.registerBeanDefinition("fmGeneric", factoryMethodDefinitionGeneric); @@ -2618,7 +2638,7 @@ private void findTypeOfPrototypeFactoryMethodOnBeanInstance(boolean singleton) { cvals.addGenericArgumentValue(expectedNameFromArgs); factoryMethodDefinitionWithArgs.setConstructorArgumentValues(cvals); if (!singleton) { - factoryMethodDefinitionWithArgs.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + factoryMethodDefinitionWithArgs.setScope(BeanDefinition.SCOPE_PROTOTYPE); } lbf.registerBeanDefinition("fmWithArgs", factoryMethodDefinitionWithArgs); @@ -2676,7 +2696,7 @@ void explicitScopeInheritanceForChildBeanDefinitions() { String theChildScope = "bonanza!"; RootBeanDefinition parent = new RootBeanDefinition(); - parent.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + parent.setScope(BeanDefinition.SCOPE_PROTOTYPE); AbstractBeanDefinition child = BeanDefinitionBuilder.childBeanDefinition("parent").getBeanDefinition(); child.setBeanClass(TestBean.class); @@ -2687,14 +2707,15 @@ void explicitScopeInheritanceForChildBeanDefinitions() { factory.registerBeanDefinition("child", child); AbstractBeanDefinition def = (AbstractBeanDefinition) factory.getBeanDefinition("child"); - Object mergedBeanDefinition2 = def.getScope(); - assertThat(mergedBeanDefinition2).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(mergedBeanDefinition2); + assertThat(def.getScope()).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(theChildScope); } @Test void scopeInheritanceForChildBeanDefinitions() { + String theParentScope = "bonanza!"; + RootBeanDefinition parent = new RootBeanDefinition(); - parent.setScope("bonanza!"); + parent.setScope(theParentScope); AbstractBeanDefinition child = new ChildBeanDefinition("parent"); child.setBeanClass(TestBean.class); @@ -2704,8 +2725,7 @@ void scopeInheritanceForChildBeanDefinitions() { factory.registerBeanDefinition("child", child); BeanDefinition def = factory.getMergedBeanDefinition("child"); - Object mergedBeanDefinition2 = def.getScope(); - assertThat(mergedBeanDefinition2).as("Child 'scope' not inherited").isEqualTo(mergedBeanDefinition2); + assertThat(def.getScope()).as("Child 'scope' not inherited").isEqualTo(theParentScope); } @Test @@ -2721,7 +2741,7 @@ void fieldSettingWithInstantiationAwarePostProcessorWithShortCircuit() { private void doTestFieldSettingWithInstantiationAwarePostProcessor(final boolean skipPropertyPopulation) { RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); int ageSetByPropertyValue = 27; - bd.getPropertyValues().addPropertyValue(new PropertyValue("age", new Integer(ageSetByPropertyValue))); + bd.getPropertyValues().addPropertyValue(new PropertyValue("age", ageSetByPropertyValue)); lbf.registerBeanDefinition("test", bd); final String nameSetOnField = "nameSetOnField"; lbf.addBeanPostProcessor(new InstantiationAwareBeanPostProcessorAdapter() { @@ -2741,15 +2761,12 @@ public boolean postProcessAfterInstantiation(Object bean, String beanName) throw }); lbf.preInstantiateSingletons(); TestBean tb = (TestBean) lbf.getBean("test"); - Object mergedBeanDefinition2 = tb.getName(); - assertThat(mergedBeanDefinition2).as("Name was set on field by IAPP").isEqualTo(mergedBeanDefinition2); + assertThat(tb.getName()).as("Name was set on field by IAPP").isEqualTo(nameSetOnField); if (!skipPropertyPopulation) { - Object mergedBeanDefinition21 = tb.getAge(); - assertThat(mergedBeanDefinition21).as("Property value still set").isEqualTo(mergedBeanDefinition21); + assertThat(tb.getAge()).as("Property value still set").isEqualTo(ageSetByPropertyValue); } else { - Object mergedBeanDefinition21 = tb.getAge(); - assertThat(mergedBeanDefinition21).as("Property value was NOT set and still has default value").isEqualTo(mergedBeanDefinition21); + assertThat(tb.getAge()).as("Property value was NOT set and still has default value").isEqualTo(0); } } @@ -2757,7 +2774,7 @@ public boolean postProcessAfterInstantiation(Object bean, String beanName) throw @SuppressWarnings({ "unchecked", "rawtypes" }) void initSecurityAwarePrototypeBean() { RootBeanDefinition bd = new RootBeanDefinition(TestSecuredBean.class); - bd.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bd.setInitMethodName("init"); lbf.registerBeanDefinition("test", bd); final Subject subject = new Subject(); @@ -3232,7 +3249,7 @@ public Object convertIfNecessary(Object value, @Nullable Class requiredType) { } } else if (value instanceof String && int.class.isAssignableFrom(requiredType)) { - return new Integer(5); + return 5; } else { return value; @@ -3253,38 +3270,6 @@ public Object convertIfNecessary(Object value, @Nullable Class requiredType, @Nu } - private static class TestPrincipal implements Principal { - - private String name; - - public TestPrincipal(String name) { - this.name = name; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof TestPrincipal)) { - return false; - } - TestPrincipal p = (TestPrincipal) obj; - return this.name.equals(p.name); - } - - @Override - public int hashCode() { - return this.name.hashCode(); - } - } - - @SuppressWarnings("unused") private static class TestSecuredBean { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java index 3bffa8ca1fae..1e466c6da352 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java @@ -27,11 +27,11 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.io.Resource; -import org.springframework.stereotype.Component; +import org.springframework.core.testfixture.stereotype.Component; import org.springframework.util.Assert; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Rob Harrop diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/Spr5475Tests.java b/spring-beans/src/test/java/org/springframework/beans/factory/Spr5475Tests.java index 5b82ef031ffe..846f6f6696c7 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/Spr5475Tests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/Spr5475Tests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ * invoking a factory method is not instructive to the user and rather misleading. * * @author Chris Beams + * @author Juergen Hoeller */ public class Spr5475Tests { @@ -40,7 +41,8 @@ public void noArgFactoryMethodInvokedWithOneArg() { rootBeanDefinition(Foo.class) .setFactoryMethod("noArgFactory") .addConstructorArgValue("bogusArg").getBeanDefinition(), - "Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(String)'. " + + "Error creating bean with name 'foo': No matching factory method found on class " + + "[org.springframework.beans.factory.Spr5475Tests$Foo]: factory method 'noArgFactory(String)'. " + "Check that a method with the specified name and arguments exists and that it is static."); } @@ -51,7 +53,8 @@ public void noArgFactoryMethodInvokedWithTwoArgs() { .setFactoryMethod("noArgFactory") .addConstructorArgValue("bogusArg1") .addConstructorArgValue("bogusArg2".getBytes()).getBeanDefinition(), - "Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(String,byte[])'. " + + "Error creating bean with name 'foo': No matching factory method found on class " + + "[org.springframework.beans.factory.Spr5475Tests$Foo]: factory method 'noArgFactory(String,byte[])'. " + "Check that a method with the specified name and arguments exists and that it is static."); } @@ -65,7 +68,8 @@ public void noArgFactoryMethodInvokedWithTwoArgsAndTypesSpecified() { def.setConstructorArgumentValues(cav); assertExceptionMessageForMisconfiguredFactoryMethod(def, - "Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(CharSequence,byte[])'. " + + "Error creating bean with name 'foo': No matching factory method found on class " + + "[org.springframework.beans.factory.Spr5475Tests$Foo]: factory method 'noArgFactory(CharSequence,byte[])'. " + "Check that a method with the specified name and arguments exists and that it is static."); } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java index ce0add1cee8a..1e6b7cdd5ece 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,16 +64,16 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.IndexedTestBean; +import org.springframework.beans.testfixture.beans.NestedTestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.Ordered; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.IndexedTestBean; -import org.springframework.tests.sample.beans.NestedTestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.core.testfixture.io.SerializationTestUtils; import org.springframework.util.ReflectionUtils; -import org.springframework.util.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -120,7 +120,7 @@ public void testIncompleteBeanDefinition() { @Test public void testResourceInjection() { RootBeanDefinition bd = new RootBeanDefinition(ResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -137,7 +137,7 @@ public void testResourceInjection() { @Test public void testExtendedResourceInjection() { RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -255,7 +255,7 @@ public void testExtendedResourceInjectionWithDefaultMethod() { public void testExtendedResourceInjectionWithAtRequired() { bf.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -297,10 +297,125 @@ public void testOptionalResourceInjection() { assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2); } + @Test + public void testOptionalResourceInjectionWithSingletonRemoval() { + RootBeanDefinition rbd = new RootBeanDefinition(OptionalResourceInjectionBean.class); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", rbd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + IndexedTestBean itb = new IndexedTestBean(); + bf.registerSingleton("indexedTestBean", itb); + NestedTestBean ntb1 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean1", ntb1); + NestedTestBean ntb2 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean2", ntb2); + + OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(tb); + assertThat(bean.getTestBean2()).isSameAs(tb); + assertThat(bean.getTestBean3()).isSameAs(tb); + assertThat(bean.getTestBean4()).isSameAs(tb); + assertThat(bean.getIndexedTestBean()).isSameAs(itb); + assertThat(bean.getNestedTestBeans().length).isEqualTo(2); + assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1); + assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2); + assertThat(bean.nestedTestBeansField.length).isEqualTo(2); + assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1); + assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2); + + bf.destroySingleton("testBean"); + + bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isNull(); + assertThat(bean.getTestBean2()).isNull(); + assertThat(bean.getTestBean3()).isNull(); + assertThat(bean.getTestBean4()).isNull(); + assertThat(bean.getIndexedTestBean()).isSameAs(itb); + assertThat(bean.getNestedTestBeans().length).isEqualTo(2); + assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1); + assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2); + assertThat(bean.nestedTestBeansField.length).isEqualTo(2); + assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1); + assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2); + + bf.registerSingleton("testBean", tb); + + bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(tb); + assertThat(bean.getTestBean2()).isSameAs(tb); + assertThat(bean.getTestBean3()).isSameAs(tb); + assertThat(bean.getTestBean4()).isSameAs(tb); + assertThat(bean.getIndexedTestBean()).isSameAs(itb); + assertThat(bean.getNestedTestBeans().length).isEqualTo(2); + assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1); + assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2); + assertThat(bean.nestedTestBeansField.length).isEqualTo(2); + assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1); + assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2); + } + + @Test + public void testOptionalResourceInjectionWithBeanDefinitionRemoval() { + RootBeanDefinition rbd = new RootBeanDefinition(OptionalResourceInjectionBean.class); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", rbd); + bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class)); + IndexedTestBean itb = new IndexedTestBean(); + bf.registerSingleton("indexedTestBean", itb); + NestedTestBean ntb1 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean1", ntb1); + NestedTestBean ntb2 = new NestedTestBean(); + bf.registerSingleton("nestedTestBean2", ntb2); + + OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean")); + assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean")); + assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean")); + assertThat(bean.getTestBean4()).isSameAs(bf.getBean("testBean")); + assertThat(bean.getIndexedTestBean()).isSameAs(itb); + assertThat(bean.getNestedTestBeans().length).isEqualTo(2); + assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1); + assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2); + assertThat(bean.nestedTestBeansField.length).isEqualTo(2); + assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1); + assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2); + + bf.removeBeanDefinition("testBean"); + + bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isNull(); + assertThat(bean.getTestBean2()).isNull(); + assertThat(bean.getTestBean3()).isNull(); + assertThat(bean.getTestBean4()).isNull(); + assertThat(bean.getIndexedTestBean()).isSameAs(itb); + assertThat(bean.getNestedTestBeans().length).isEqualTo(2); + assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1); + assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2); + assertThat(bean.nestedTestBeansField.length).isEqualTo(2); + assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1); + assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2); + + bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class)); + + bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean")); + assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean")); + assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean")); + assertThat(bean.getTestBean4()).isSameAs(bf.getBean("testBean")); + assertThat(bean.getIndexedTestBean()).isSameAs(itb); + assertThat(bean.getNestedTestBeans().length).isEqualTo(2); + assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1); + assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2); + assertThat(bean.nestedTestBeansField.length).isEqualTo(2); + assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1); + assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2); + } + @Test public void testOptionalCollectionResourceInjection() { RootBeanDefinition rbd = new RootBeanDefinition(OptionalCollectionResourceInjectionBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", rbd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -333,7 +448,7 @@ public void testOptionalCollectionResourceInjection() { @Test public void testOptionalCollectionResourceInjectionWithSingleElement() { RootBeanDefinition rbd = new RootBeanDefinition(OptionalCollectionResourceInjectionBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", rbd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -441,7 +556,7 @@ public void testAnnotationOrderedResourceInjection() { @Test public void testOrderedCollectionResourceInjection() { RootBeanDefinition rbd = new RootBeanDefinition(OptionalCollectionResourceInjectionBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", rbd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -476,7 +591,7 @@ public void testOrderedCollectionResourceInjection() { @Test public void testAnnotationOrderedCollectionResourceInjection() { RootBeanDefinition rbd = new RootBeanDefinition(OptionalCollectionResourceInjectionBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", rbd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -509,7 +624,7 @@ public void testAnnotationOrderedCollectionResourceInjection() { @Test public void testConstructorResourceInjection() { RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -533,10 +648,87 @@ public void testConstructorResourceInjection() { assertThat(bean.getBeanFactory()).isSameAs(bf); } + @Test + public void testConstructorResourceInjectionWithSingletonRemoval() { + RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + NestedTestBean ntb = new NestedTestBean(); + bf.registerSingleton("nestedTestBean", ntb); + + ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(tb); + assertThat(bean.getTestBean2()).isSameAs(tb); + assertThat(bean.getTestBean3()).isSameAs(tb); + assertThat(bean.getTestBean4()).isSameAs(tb); + assertThat(bean.getNestedTestBean()).isSameAs(ntb); + assertThat(bean.getBeanFactory()).isSameAs(bf); + + bf.destroySingleton("nestedTestBean"); + + bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(tb); + assertThat(bean.getTestBean2()).isSameAs(tb); + assertThat(bean.getTestBean3()).isSameAs(tb); + assertThat(bean.getTestBean4()).isSameAs(tb); + assertThat(bean.getNestedTestBean()).isNull(); + assertThat(bean.getBeanFactory()).isSameAs(bf); + + bf.registerSingleton("nestedTestBean", ntb); + + bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(tb); + assertThat(bean.getTestBean2()).isSameAs(tb); + assertThat(bean.getTestBean3()).isSameAs(tb); + assertThat(bean.getTestBean4()).isSameAs(tb); + assertThat(bean.getNestedTestBean()).isSameAs(ntb); + assertThat(bean.getBeanFactory()).isSameAs(bf); + } + + @Test + public void testConstructorResourceInjectionWithBeanDefinitionRemoval() { + RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + TestBean tb = new TestBean(); + bf.registerSingleton("testBean", tb); + bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class)); + + ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(tb); + assertThat(bean.getTestBean2()).isSameAs(tb); + assertThat(bean.getTestBean3()).isSameAs(tb); + assertThat(bean.getTestBean4()).isSameAs(tb); + assertThat(bean.getNestedTestBean()).isSameAs(bf.getBean("nestedTestBean")); + assertThat(bean.getBeanFactory()).isSameAs(bf); + + bf.removeBeanDefinition("nestedTestBean"); + + bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(tb); + assertThat(bean.getTestBean2()).isSameAs(tb); + assertThat(bean.getTestBean3()).isSameAs(tb); + assertThat(bean.getTestBean4()).isSameAs(tb); + assertThat(bean.getNestedTestBean()).isNull(); + assertThat(bean.getBeanFactory()).isSameAs(bf); + + bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class)); + + bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertThat(bean.getTestBean()).isSameAs(tb); + assertThat(bean.getTestBean2()).isSameAs(tb); + assertThat(bean.getTestBean3()).isSameAs(tb); + assertThat(bean.getTestBean4()).isSameAs(tb); + assertThat(bean.getNestedTestBean()).isSameAs(bf.getBean("nestedTestBean")); + assertThat(bean.getBeanFactory()).isSameAs(bf); + } + @Test public void testConstructorResourceInjectionWithNullFromFactoryBean() { RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -563,7 +755,7 @@ public void testConstructorResourceInjectionWithNullFromFactoryBean() { @Test public void testConstructorResourceInjectionWithNullFromFactoryMethod() { RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); RootBeanDefinition tb = new RootBeanDefinition(NullFactoryMethods.class); tb.setFactoryMethodName("createTestBean"); @@ -818,7 +1010,7 @@ public void testConstructorResourceInjectionWithMultipleCandidatesAndDefaultFall @Test public void testConstructorInjectionWithMap() { RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb1 = new TestBean("tb1"); bf.registerSingleton("testBean1", tb1); @@ -840,7 +1032,7 @@ public void testConstructorInjectionWithMap() { @Test public void testFieldInjectionWithMap() { RootBeanDefinition bd = new RootBeanDefinition(MapFieldInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb1 = new TestBean("tb1"); TestBean tb2 = new TestBean("tb2"); @@ -865,7 +1057,7 @@ public void testFieldInjectionWithMap() { @Test public void testMethodInjectionWithMap() { RootBeanDefinition bd = new RootBeanDefinition(MapMethodInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -921,7 +1113,7 @@ public void testMethodInjectionWithMapAndNoMatches() { @Test public void testConstructorInjectionWithTypedMapAsBean() { RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); MyTestBeanMap tbm = new MyTestBeanMap(); tbm.put("testBean1", new TestBean("tb1")); @@ -938,7 +1130,7 @@ public void testConstructorInjectionWithTypedMapAsBean() { @Test public void testConstructorInjectionWithPlainMapAsBean() { RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); RootBeanDefinition tbm = new RootBeanDefinition(CollectionFactoryMethods.class); tbm.setUniqueFactoryMethodName("testBeanMap"); @@ -954,7 +1146,7 @@ public void testConstructorInjectionWithPlainMapAsBean() { @Test public void testConstructorInjectionWithCustomMapAsBean() { RootBeanDefinition bd = new RootBeanDefinition(CustomMapConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); RootBeanDefinition tbm = new RootBeanDefinition(CustomCollectionFactoryMethods.class); tbm.setUniqueFactoryMethodName("testBeanMap"); @@ -971,7 +1163,7 @@ public void testConstructorInjectionWithCustomMapAsBean() { @Test public void testConstructorInjectionWithPlainHashMapAsBean() { RootBeanDefinition bd = new RootBeanDefinition(QualifiedMapConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); bf.registerBeanDefinition("myTestBeanMap", new RootBeanDefinition(HashMap.class)); @@ -984,7 +1176,7 @@ public void testConstructorInjectionWithPlainHashMapAsBean() { @Test public void testConstructorInjectionWithTypedSetAsBean() { RootBeanDefinition bd = new RootBeanDefinition(SetConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); MyTestBeanSet tbs = new MyTestBeanSet(); tbs.add(new TestBean("tb1")); @@ -1001,7 +1193,7 @@ public void testConstructorInjectionWithTypedSetAsBean() { @Test public void testConstructorInjectionWithPlainSetAsBean() { RootBeanDefinition bd = new RootBeanDefinition(SetConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); RootBeanDefinition tbs = new RootBeanDefinition(CollectionFactoryMethods.class); tbs.setUniqueFactoryMethodName("testBeanSet"); @@ -1017,7 +1209,7 @@ public void testConstructorInjectionWithPlainSetAsBean() { @Test public void testConstructorInjectionWithCustomSetAsBean() { RootBeanDefinition bd = new RootBeanDefinition(CustomSetConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); RootBeanDefinition tbs = new RootBeanDefinition(CustomCollectionFactoryMethods.class); tbs.setUniqueFactoryMethodName("testBeanSet"); @@ -1143,7 +1335,7 @@ public void testObjectFactorySerialization() throws Exception { public void testObjectProviderInjectionWithPrototype() { bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class)); RootBeanDefinition tbd = new RootBeanDefinition(TestBean.class); - tbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + tbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("testBean", tbd); ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean"); @@ -1515,7 +1707,7 @@ public void testBeanAutowiredWithFactoryBean() { @Test public void testGenericsBasedFieldInjection() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); String sv = "X"; bf.registerSingleton("stringValue", sv); @@ -1560,7 +1752,7 @@ public void testGenericsBasedFieldInjection() { @Test public void testGenericsBasedFieldInjectionWithSubstitutedVariables() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithSubstitutedVariables.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); String sv = "X"; bf.registerSingleton("stringValue", sv); @@ -1605,7 +1797,7 @@ public void testGenericsBasedFieldInjectionWithSubstitutedVariables() { @Test public void testGenericsBasedFieldInjectionWithQualifiers() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithQualifiers.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); StringRepository sr = new StringRepository(); bf.registerSingleton("stringRepo", sr); @@ -1632,7 +1824,7 @@ public void testGenericsBasedFieldInjectionWithQualifiers() { @Test public void testGenericsBasedFieldInjectionWithMocks() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithQualifiers.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class); @@ -1671,7 +1863,7 @@ public void testGenericsBasedFieldInjectionWithMocks() { @Test public void testGenericsBasedFieldInjectionWithSimpleMatch() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithSimpleMatch.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); bf.registerSingleton("repo", new StringRepository()); @@ -1699,7 +1891,7 @@ public void testGenericsBasedFieldInjectionWithSimpleMatch() { @Test public void testGenericsBasedFactoryBeanInjectionWithBeanDefinition() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryFactoryBeanInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); bf.registerBeanDefinition("repoFactoryBean", new RootBeanDefinition(RepositoryFactoryBean.class)); @@ -1711,7 +1903,7 @@ public void testGenericsBasedFactoryBeanInjectionWithBeanDefinition() { @Test public void testGenericsBasedFactoryBeanInjectionWithSingletonBean() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryFactoryBeanInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); bf.registerSingleton("repoFactoryBean", new RepositoryFactoryBean<>()); @@ -1723,7 +1915,7 @@ public void testGenericsBasedFactoryBeanInjectionWithSingletonBean() { @Test public void testGenericsBasedFieldInjectionWithSimpleMatchAndMock() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithSimpleMatch.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class); @@ -1755,7 +1947,7 @@ public void testGenericsBasedFieldInjectionWithSimpleMatchAndMock() { @Test public void testGenericsBasedFieldInjectionWithSimpleMatchAndMockito() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithSimpleMatch.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); RootBeanDefinition rbd = new RootBeanDefinition(); @@ -1786,7 +1978,7 @@ public void testGenericsBasedFieldInjectionWithSimpleMatchAndMockito() { @Test public void testGenericsBasedMethodInjection() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); String sv = "X"; bf.registerSingleton("stringValue", sv); @@ -1831,7 +2023,7 @@ public void testGenericsBasedMethodInjection() { @Test public void testGenericsBasedMethodInjectionWithSubstitutedVariables() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBeanWithSubstitutedVariables.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); String sv = "X"; bf.registerSingleton("stringValue", sv); @@ -1876,7 +2068,7 @@ public void testGenericsBasedMethodInjectionWithSubstitutedVariables() { @Test public void testGenericsBasedConstructorInjection() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); StringRepository sr = new StringRepository(); bf.registerSingleton("stringRepo", sr); @@ -1904,7 +2096,7 @@ public void testGenericsBasedConstructorInjection() { @SuppressWarnings("rawtypes") public void testGenericsBasedConstructorInjectionWithNonTypedTarget() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); GenericRepository gr = new GenericRepository(); bf.registerSingleton("genericRepo", gr); @@ -1929,7 +2121,7 @@ public void testGenericsBasedConstructorInjectionWithNonTypedTarget() { @Test public void testGenericsBasedConstructorInjectionWithNonGenericTarget() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); SimpleRepository ngr = new SimpleRepository(); bf.registerSingleton("simpleRepo", ngr); @@ -1955,7 +2147,7 @@ public void testGenericsBasedConstructorInjectionWithNonGenericTarget() { @SuppressWarnings("rawtypes") public void testGenericsBasedConstructorInjectionWithMixedTargets() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); StringRepository sr = new StringRepository(); bf.registerSingleton("stringRepo", sr); @@ -1982,7 +2174,7 @@ public void testGenericsBasedConstructorInjectionWithMixedTargets() { @Test public void testGenericsBasedConstructorInjectionWithMixedTargetsIncludingNonGeneric() { RootBeanDefinition bd = new RootBeanDefinition(RepositoryConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); StringRepository sr = new StringRepository(); bf.registerSingleton("stringRepo", sr); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurerTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurerTests.java index 3454c28d9c22..02a87f6c0d4b 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurerTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurerTests.java @@ -25,7 +25,7 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * Unit tests for {@link CustomAutowireConfigurer}. diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/InjectAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/InjectAnnotationBeanPostProcessorTests.java index af5e0258e6b2..43e57e7d26a8 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/InjectAnnotationBeanPostProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/InjectAnnotationBeanPostProcessorTests.java @@ -40,11 +40,11 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.IndexedTestBean; -import org.springframework.tests.sample.beans.NestedTestBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.util.SerializationTestUtils; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.IndexedTestBean; +import org.springframework.beans.testfixture.beans.NestedTestBean; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -94,7 +94,7 @@ public void testIncompleteBeanDefinition() { @Test public void testResourceInjection() { RootBeanDefinition bd = new RootBeanDefinition(ResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -111,7 +111,7 @@ public void testResourceInjection() { @Test public void testExtendedResourceInjection() { RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -160,7 +160,7 @@ public void testExtendedResourceInjectionWithOverriding() { public void testExtendedResourceInjectionWithAtRequired() { bf.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -179,7 +179,7 @@ public void testExtendedResourceInjectionWithAtRequired() { @Test public void testConstructorResourceInjection() { RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); @@ -236,7 +236,7 @@ public void testConstructorResourceInjectionWithMultipleCandidatesAndFallback() @Test public void testConstructorInjectionWithMap() { RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb1 = new TestBean(); TestBean tb2 = new TestBean(); @@ -261,7 +261,7 @@ public void testConstructorInjectionWithMap() { @Test public void testFieldInjectionWithMap() { RootBeanDefinition bd = new RootBeanDefinition(MapFieldInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb1 = new TestBean(); TestBean tb2 = new TestBean(); @@ -286,7 +286,7 @@ public void testFieldInjectionWithMap() { @Test public void testMethodInjectionWithMap() { RootBeanDefinition bd = new RootBeanDefinition(MapMethodInjectionBean.class); - bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bf.registerBeanDefinition("annotatedBean", bd); TestBean tb = new TestBean(); bf.registerSingleton("testBean", tb); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/LookupAnnotationTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/LookupAnnotationTests.java index 388b4a8bfa80..bd30b5b44c24 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/LookupAnnotationTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/LookupAnnotationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,9 +19,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -44,7 +45,7 @@ public void setup() { beanFactory.registerBeanDefinition("abstractBean", new RootBeanDefinition(AbstractBean.class)); beanFactory.registerBeanDefinition("beanConsumer", new RootBeanDefinition(BeanConsumer.class)); RootBeanDefinition tbd = new RootBeanDefinition(TestBean.class); - tbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + tbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); beanFactory.registerBeanDefinition("testBean", tbd); } @@ -107,10 +108,23 @@ public void testWithEarlyInjection() { assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean); } + @Test // gh-25806 + public void testWithNullBean() { + RootBeanDefinition tbd = new RootBeanDefinition(TestBean.class, () -> null); + tbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); + beanFactory.registerBeanDefinition("testBean", tbd); + + AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean; + assertThat(bean).isNotNull(); + Object expected = bean.get(); + assertThat(expected).isNull(); + assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean); + } + public static abstract class AbstractBean { - @Lookup + @Lookup("testBean") public abstract TestBean get(); @Lookup diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/CustomEditorConfigurerTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/CustomEditorConfigurerTests.java index 921e76100c5c..a94425ccf1aa 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/CustomEditorConfigurerTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/CustomEditorConfigurerTests.java @@ -33,7 +33,7 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.propertyeditors.CustomDateEditor; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests.java index cc20dc84e4d3..b697500fb343 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,10 +22,10 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * Unit tests for {@link FieldRetrievingFactoryBean}. @@ -41,7 +41,7 @@ public void testStaticField() throws Exception { FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); fr.setStaticField("java.sql.Connection.TRANSACTION_SERIALIZABLE"); fr.afterPropertiesSet(); - assertThat(fr.getObject()).isEqualTo(new Integer(Connection.TRANSACTION_SERIALIZABLE)); + assertThat(fr.getObject()).isEqualTo(Connection.TRANSACTION_SERIALIZABLE); } @Test @@ -49,7 +49,7 @@ public void testStaticFieldWithWhitespace() throws Exception { FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); fr.setStaticField(" java.sql.Connection.TRANSACTION_SERIALIZABLE "); fr.afterPropertiesSet(); - assertThat(fr.getObject()).isEqualTo(new Integer(Connection.TRANSACTION_SERIALIZABLE)); + assertThat(fr.getObject()).isEqualTo(Connection.TRANSACTION_SERIALIZABLE); } @Test @@ -58,7 +58,7 @@ public void testStaticFieldViaClassAndFieldName() throws Exception { fr.setTargetClass(Connection.class); fr.setTargetField("TRANSACTION_SERIALIZABLE"); fr.afterPropertiesSet(); - assertThat(fr.getObject()).isEqualTo(new Integer(Connection.TRANSACTION_SERIALIZABLE)); + assertThat(fr.getObject()).isEqualTo(Connection.TRANSACTION_SERIALIZABLE); } @Test @@ -76,7 +76,7 @@ public void testNothingButBeanName() throws Exception { FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); fr.setBeanName("java.sql.Connection.TRANSACTION_SERIALIZABLE"); fr.afterPropertiesSet(); - assertThat(fr.getObject()).isEqualTo(new Integer(Connection.TRANSACTION_SERIALIZABLE)); + assertThat(fr.getObject()).isEqualTo(Connection.TRANSACTION_SERIALIZABLE); } @Test @@ -115,7 +115,7 @@ public void testJustTargetObject() throws Exception { @Test public void testWithConstantOnClassWithPackageLevelVisibility() throws Exception { FieldRetrievingFactoryBean fr = new FieldRetrievingFactoryBean(); - fr.setBeanName("org.springframework.tests.sample.beans.PackageLevelVisibleBean.CONSTANT"); + fr.setBeanName("org.springframework.beans.testfixture.beans.PackageLevelVisibleBean.CONSTANT"); fr.afterPropertiesSet(); assertThat(fr.getObject()).isEqualTo("Wuby"); } @@ -127,8 +127,8 @@ public void testBeanNameSyntaxWithBeanFactory() throws Exception { qualifiedResource(FieldRetrievingFactoryBeanTests.class, "context.xml")); TestBean testBean = (TestBean) bf.getBean("testBean"); - assertThat(testBean.getSomeIntegerArray()[0]).isEqualTo(new Integer(Connection.TRANSACTION_SERIALIZABLE)); - assertThat(testBean.getSomeIntegerArray()[1]).isEqualTo(new Integer(Connection.TRANSACTION_SERIALIZABLE)); + assertThat(testBean.getSomeIntegerArray()[0]).isEqualTo(Connection.TRANSACTION_SERIALIZABLE); + assertThat(testBean.getSomeIntegerArray()[1]).isEqualTo(Connection.TRANSACTION_SERIALIZABLE); } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java index 02066e98a455..97805143da86 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java @@ -28,13 +28,13 @@ import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.util.SerializationTestUtils; +import org.springframework.core.testfixture.io.SerializationTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Colin Sampaleanu diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertiesFactoryBeanTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertiesFactoryBeanTests.java index e7b68287893d..27a00cb5c47c 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertiesFactoryBeanTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertiesFactoryBeanTests.java @@ -23,7 +23,7 @@ import org.springframework.core.io.Resource; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * Unit tests for {@link PropertiesFactoryBean}. diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java index 0c7fcc4a4c1f..bc0c7cce84f7 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,12 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.Resource; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * Unit tests for {@link PropertyPathFactoryBean}. @@ -43,9 +43,9 @@ public class PropertyPathFactoryBeanTests { public void testPropertyPathFactoryBeanWithSingletonResult() { DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONTEXT); - assertThat(xbf.getBean("propertyPath1")).isEqualTo(new Integer(12)); - assertThat(xbf.getBean("propertyPath2")).isEqualTo(new Integer(11)); - assertThat(xbf.getBean("tb.age")).isEqualTo(new Integer(10)); + assertThat(xbf.getBean("propertyPath1")).isEqualTo(12); + assertThat(xbf.getBean("propertyPath2")).isEqualTo(11); + assertThat(xbf.getBean("tb.age")).isEqualTo(10); assertThat(xbf.getType("otb.spouse")).isEqualTo(ITestBean.class); Object result1 = xbf.getBean("otb.spouse"); Object result2 = xbf.getBean("otb.spouse"); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java index ac0643b3f28c..13d8b138ff43 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java @@ -24,9 +24,9 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java index 9d5b3909ce60..5dd76865de42 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,15 +39,15 @@ import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.support.ManagedSet; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.testfixture.beans.IndexedTestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.Resource; -import org.springframework.tests.sample.beans.IndexedTestBean; -import org.springframework.tests.sample.beans.TestBean; import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * Unit tests for various {@link PropertyResourceConfigurer} implementations including: @@ -414,7 +414,7 @@ private void doTestPropertyPlaceholderConfigurer(boolean parentChildSeparation) assertThat(tb2.getSomeSet().size()).isEqualTo(3); assertThat(tb2.getSomeSet().contains("na98me")).isTrue(); assertThat(tb2.getSomeSet().contains(tb2)).isTrue(); - assertThat(tb2.getSomeSet().contains(new Integer(98))).isTrue(); + assertThat(tb2.getSomeSet().contains(98)).isTrue(); assertThat(tb2.getSomeMap().size()).isEqualTo(6); assertThat(tb2.getSomeMap().get("key98")).isEqualTo("98"); assertThat(tb2.getSomeMap().get("key98ref")).isEqualTo(tb2); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/SimpleScopeTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/SimpleScopeTests.java index 297c4a655ca6..38b10b562f5c 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/SimpleScopeTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/SimpleScopeTests.java @@ -25,10 +25,10 @@ import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * Simple test to illustrate and verify scope usage. diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java index 0bacf2162582..60fbd272ce2c 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,13 @@ package org.springframework.beans.factory.config; +import java.net.URL; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; +import org.yaml.snakeyaml.constructor.ConstructorException; import org.yaml.snakeyaml.parser.ParserException; import org.yaml.snakeyaml.scanner.ScannerException; @@ -29,6 +31,7 @@ import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.entry; /** * Tests for {@link YamlProcessor}. @@ -37,14 +40,14 @@ * @author Juergen Hoeller * @author Sam Brannen */ -public class YamlProcessorTests { +class YamlProcessorTests { private final YamlProcessor processor = new YamlProcessor() {}; @Test - public void arrayConvertedToIndexedBeanReference() { - this.processor.setResources(new ByteArrayResource("foo: bar\nbar: [1,2,3]".getBytes())); + void arrayConvertedToIndexedBeanReference() { + setYaml("foo: bar\nbar: [1,2,3]"); this.processor.process((properties, map) -> { assertThat(properties.size()).isEqualTo(4); assertThat(properties.get("foo")).isEqualTo("bar"); @@ -59,30 +62,30 @@ public void arrayConvertedToIndexedBeanReference() { } @Test - public void stringResource() { - this.processor.setResources(new ByteArrayResource("foo # a document that is a literal".getBytes())); + void stringResource() { + setYaml("foo # a document that is a literal"); this.processor.process((properties, map) -> assertThat(map.get("document")).isEqualTo("foo")); } @Test - public void badDocumentStart() { - this.processor.setResources(new ByteArrayResource("foo # a document\nbar: baz".getBytes())); + void badDocumentStart() { + setYaml("foo # a document\nbar: baz"); assertThatExceptionOfType(ParserException.class) .isThrownBy(() -> this.processor.process((properties, map) -> {})) .withMessageContaining("line 2, column 1"); } @Test - public void badResource() { - this.processor.setResources(new ByteArrayResource("foo: bar\ncd\nspam:\n foo: baz".getBytes())); + void badResource() { + setYaml("foo: bar\ncd\nspam:\n foo: baz"); assertThatExceptionOfType(ScannerException.class) .isThrownBy(() -> this.processor.process((properties, map) -> {})) .withMessageContaining("line 3, column 1"); } @Test - public void mapConvertedToIndexedBeanReference() { - this.processor.setResources(new ByteArrayResource("foo: bar\nbar:\n spam: bucket".getBytes())); + void mapConvertedToIndexedBeanReference() { + setYaml("foo: bar\nbar:\n spam: bucket"); this.processor.process((properties, map) -> { assertThat(properties.get("bar.spam")).isEqualTo("bucket"); assertThat(properties).hasSize(2); @@ -90,8 +93,8 @@ public void mapConvertedToIndexedBeanReference() { } @Test - public void integerKeyBehaves() { - this.processor.setResources(new ByteArrayResource("foo: bar\n1: bar".getBytes())); + void integerKeyBehaves() { + setYaml("foo: bar\n1: bar"); this.processor.process((properties, map) -> { assertThat(properties.get("[1]")).isEqualTo("bar"); assertThat(properties).hasSize(2); @@ -99,8 +102,8 @@ public void integerKeyBehaves() { } @Test - public void integerDeepKeyBehaves() { - this.processor.setResources(new ByteArrayResource("foo:\n 1: bar".getBytes())); + void integerDeepKeyBehaves() { + setYaml("foo:\n 1: bar"); this.processor.process((properties, map) -> { assertThat(properties.get("foo[1]")).isEqualTo("bar"); assertThat(properties).hasSize(1); @@ -109,8 +112,8 @@ public void integerDeepKeyBehaves() { @Test @SuppressWarnings("unchecked") - public void flattenedMapIsSameAsPropertiesButOrdered() { - this.processor.setResources(new ByteArrayResource("cat: dog\nfoo: bar\nbar:\n spam: bucket".getBytes())); + void flattenedMapIsSameAsPropertiesButOrdered() { + setYaml("cat: dog\nfoo: bar\nbar:\n spam: bucket"); this.processor.process((properties, map) -> { Map flattenedMap = processor.getFlattenedMap(map); assertThat(flattenedMap).isInstanceOf(LinkedHashMap.class); @@ -134,4 +137,43 @@ public void flattenedMapIsSameAsPropertiesButOrdered() { }); } + @Test + void customTypeSupportedByDefault() throws Exception { + URL url = new URL("https://localhost:9000/"); + setYaml("value: !!java.net.URL [\"" + url + "\"]"); + + this.processor.process((properties, map) -> { + assertThat(properties).containsExactly(entry("value", url)); + assertThat(map).containsExactly(entry("value", url)); + }); + } + + @Test + void customTypesSupportedDueToExplicitConfiguration() throws Exception { + this.processor.setSupportedTypes(URL.class, String.class); + + URL url = new URL("https://localhost:9000/"); + setYaml("value: !!java.net.URL [!!java.lang.String [\"" + url + "\"]]"); + + this.processor.process((properties, map) -> { + assertThat(properties).containsExactly(entry("value", url)); + assertThat(map).containsExactly(entry("value", url)); + }); + } + + @Test + void customTypeNotSupportedDueToExplicitConfiguration() { + this.processor.setSupportedTypes(List.class); + + setYaml("value: !!java.net.URL [\"https://localhost:9000/\"]"); + + assertThatExceptionOfType(ConstructorException.class) + .isThrownBy(() -> this.processor.process((properties, map) -> {})) + .withMessageContaining("Unsupported type encountered in YAML document: java.net.URL"); + } + + private void setYaml(String yaml) { + this.processor.setResources(new ByteArrayResource(yaml.getBytes())); + } + } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java index 33caa90d5734..34abf223af41 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java @@ -24,10 +24,10 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestResourceUtils.qualifiedResource; +import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; /** * @author Rob Harrop diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionBuilderTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionBuilderTests.java index 6d416cdcf798..ec157df512c2 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionBuilderTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionBuilderTests.java @@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java index a7af6e8f2924..de770309e058 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; @@ -73,19 +73,19 @@ public void beanDefinitionEqualityWithPropertyValues() { public void beanDefinitionEqualityWithConstructorArguments() { RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); bd.getConstructorArgumentValues().addGenericArgumentValue("test"); - bd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5)); + bd.getConstructorArgumentValues().addIndexedArgumentValue(1, 5); RootBeanDefinition otherBd = new RootBeanDefinition(TestBean.class); otherBd.getConstructorArgumentValues().addGenericArgumentValue("test"); boolean condition3 = !bd.equals(otherBd); assertThat(condition3).isTrue(); boolean condition2 = !otherBd.equals(bd); assertThat(condition2).isTrue(); - otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(9)); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, 9); boolean condition1 = !bd.equals(otherBd); assertThat(condition1).isTrue(); boolean condition = !otherBd.equals(bd); assertThat(condition).isTrue(); - otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5)); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, 5); assertThat(bd.equals(otherBd)).isTrue(); assertThat(otherBd.equals(bd)).isTrue(); assertThat(bd.hashCode() == otherBd.hashCode()).isTrue(); @@ -95,20 +95,20 @@ public void beanDefinitionEqualityWithConstructorArguments() { public void beanDefinitionEqualityWithTypedConstructorArguments() { RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); bd.getConstructorArgumentValues().addGenericArgumentValue("test", "int"); - bd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5), "long"); + bd.getConstructorArgumentValues().addIndexedArgumentValue(1, 5, "long"); RootBeanDefinition otherBd = new RootBeanDefinition(TestBean.class); otherBd.getConstructorArgumentValues().addGenericArgumentValue("test", "int"); - otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5)); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, 5); boolean condition3 = !bd.equals(otherBd); assertThat(condition3).isTrue(); boolean condition2 = !otherBd.equals(bd); assertThat(condition2).isTrue(); - otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5), "int"); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, 5, "int"); boolean condition1 = !bd.equals(otherBd); assertThat(condition1).isTrue(); boolean condition = !otherBd.equals(bd); assertThat(condition).isTrue(); - otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5), "long"); + otherBd.getConstructorArgumentValues().addIndexedArgumentValue(1, 5, "long"); assertThat(bd.equals(otherBd)).isTrue(); assertThat(otherBd.equals(bd)).isTrue(); assertThat(bd.hashCode() == otherBd.hashCode()).isTrue(); @@ -133,6 +133,16 @@ public void genericBeanDefinitionEquality() { assertThat(bd.equals(otherBd)).isTrue(); assertThat(otherBd.equals(bd)).isTrue(); assertThat(bd.hashCode() == otherBd.hashCode()).isTrue(); + + bd.getPropertyValues(); + assertThat(bd.equals(otherBd)).isTrue(); + assertThat(otherBd.equals(bd)).isTrue(); + assertThat(bd.hashCode() == otherBd.hashCode()).isTrue(); + + bd.getConstructorArgumentValues(); + assertThat(bd.equals(otherBd)).isTrue(); + assertThat(otherBd.equals(bd)).isTrue(); + assertThat(bd.hashCode() == otherBd.hashCode()).isTrue(); } @Test @@ -160,7 +170,7 @@ public void beanDefinitionHolderEquality() { public void beanDefinitionMerging() { RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); bd.getConstructorArgumentValues().addGenericArgumentValue("test"); - bd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5)); + bd.getConstructorArgumentValues().addIndexedArgumentValue(1, 5); bd.getPropertyValues().add("name", "myName"); bd.getPropertyValues().add("age", "99"); bd.setQualifiedElement(getClass()); @@ -174,8 +184,8 @@ public void beanDefinitionMerging() { assertThat(mergedBd.getPropertyValues().size()).isEqualTo(2); assertThat(mergedBd).isEqualTo(bd); - mergedBd.getConstructorArgumentValues().getArgumentValue(1, null).setValue(new Integer(9)); - assertThat(bd.getConstructorArgumentValues().getArgumentValue(1, null).getValue()).isEqualTo(new Integer(5)); + mergedBd.getConstructorArgumentValues().getArgumentValue(1, null).setValue(9); + assertThat(bd.getConstructorArgumentValues().getArgumentValue(1, null).getValue()).isEqualTo(5); assertThat(bd.getQualifiedElement()).isEqualTo(getClass()); } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java index d848f90a7e5e..6a69d4974e62 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,21 +43,21 @@ import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.beans.propertyeditors.CustomNumberEditor; +import org.springframework.beans.testfixture.beans.GenericBean; +import org.springframework.beans.testfixture.beans.GenericIntegerBean; +import org.springframework.beans.testfixture.beans.GenericSetOfIntegerBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.OverridingClassLoader; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.UrlResource; -import org.springframework.tests.EnabledForTestGroups; -import org.springframework.tests.sample.beans.GenericBean; -import org.springframework.tests.sample.beans.GenericIntegerBean; -import org.springframework.tests.sample.beans.GenericSetOfIntegerBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.core.testfixture.EnabledForTestGroups; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.springframework.tests.TestGroup.LONG_RUNNING; +import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING; /** * @author Juergen Hoeller @@ -80,8 +80,8 @@ public void testGenericSetProperty() { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); } @Test @@ -159,8 +159,8 @@ public void testGenericMapProperty() { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(new Integer(7)); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(7); } @Test @@ -191,23 +191,23 @@ public void testGenericSetConstructor() { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); } @Test public void testGenericSetConstructorWithAutowiring() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); - bf.registerSingleton("integer1", new Integer(4)); - bf.registerSingleton("integer2", new Integer(5)); + bf.registerSingleton("integer1", 4); + bf.registerSingleton("integer2", 5); RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); } @Test @@ -239,8 +239,8 @@ public void testGenericSetListConstructor() throws Exception { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); assertThat(gb.getResourceList().get(1)).isEqualTo(new UrlResource("http://localhost:9090")); } @@ -248,8 +248,8 @@ public void testGenericSetListConstructor() throws Exception { @Test public void testGenericSetListConstructorWithAutowiring() throws Exception { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); - bf.registerSingleton("integer1", new Integer(4)); - bf.registerSingleton("integer2", new Integer(5)); + bf.registerSingleton("integer1", 4); + bf.registerSingleton("integer2", 5); bf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); bf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); @@ -258,8 +258,8 @@ public void testGenericSetListConstructorWithAutowiring() throws Exception { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); assertThat(gb.getResourceList().get(1)).isEqualTo(new UrlResource("http://localhost:9090")); } @@ -296,10 +296,10 @@ public void testGenericSetMapConstructor() { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(new Integer(7)); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(7); } @Test @@ -316,8 +316,8 @@ public void testGenericMapResourceConstructor() throws Exception { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(new Integer(7)); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(7); assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); } @@ -343,8 +343,8 @@ public void testGenericMapMapConstructor() { assertThat(gb.getPlainMap().get("1")).isEqualTo("0"); assertThat(gb.getPlainMap().get("2")).isEqualTo("3"); assertThat(gb.getShortMap().size()).isEqualTo(2); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(new Integer(7)); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(7); } @Test @@ -366,8 +366,8 @@ public void testGenericMapMapConstructorWithSameRefAndConversion() { assertThat(gb.getPlainMap().get("1")).isEqualTo("0"); assertThat(gb.getPlainMap().get("2")).isEqualTo("3"); assertThat(gb.getShortMap().size()).isEqualTo(2); - assertThat(gb.getShortMap().get(new Short("1"))).isEqualTo(new Integer(0)); - assertThat(gb.getShortMap().get(new Short("2"))).isEqualTo(new Integer(3)); + assertThat(gb.getShortMap().get(new Short("1"))).isEqualTo(0); + assertThat(gb.getShortMap().get(new Short("2"))).isEqualTo(3); } @Test @@ -376,8 +376,8 @@ public void testGenericMapMapConstructorWithSameRefAndNoConversion() { RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); Map input = new HashMap<>(); - input.put(new Short((short) 1), new Integer(0)); - input.put(new Short((short) 2), new Integer(3)); + input.put(new Short((short) 1), 0); + input.put(new Short((short) 2), 3); rbd.getConstructorArgumentValues().addGenericArgumentValue(input); rbd.getConstructorArgumentValues().addGenericArgumentValue(input); @@ -386,8 +386,8 @@ public void testGenericMapMapConstructorWithSameRefAndNoConversion() { assertThat(gb.getShortMap()).isSameAs(gb.getPlainMap()); assertThat(gb.getShortMap().size()).isEqualTo(2); - assertThat(gb.getShortMap().get(new Short("1"))).isEqualTo(new Integer(0)); - assertThat(gb.getShortMap().get(new Short("2"))).isEqualTo(new Integer(3)); + assertThat(gb.getShortMap().get(new Short("1"))).isEqualTo(0); + assertThat(gb.getShortMap().get(new Short("2"))).isEqualTo(3); } @Test @@ -403,8 +403,8 @@ public void testGenericMapWithKeyTypeConstructor() { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getLongMap().get(new Long("4"))).isEqualTo("5"); - assertThat(gb.getLongMap().get(new Long("6"))).isEqualTo("7"); + assertThat(gb.getLongMap().get(4L)).isEqualTo("5"); + assertThat(gb.getLongMap().get(6L)).isEqualTo("7"); } @Test @@ -420,7 +420,7 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { Map> input = new HashMap<>(); HashSet value1 = new HashSet<>(); - value1.add(new Integer(1)); + value1.add(1); input.put("1", value1); ArrayList value2 = new ArrayList<>(); value2.add(Boolean.TRUE); @@ -431,9 +431,9 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - boolean condition1 = gb.getCollectionMap().get(new Integer(1)) instanceof HashSet; + boolean condition1 = gb.getCollectionMap().get(1) instanceof HashSet; assertThat(condition1).isTrue(); - boolean condition = gb.getCollectionMap().get(new Integer(2)) instanceof ArrayList; + boolean condition = gb.getCollectionMap().get(2) instanceof ArrayList; assertThat(condition).isTrue(); } @@ -452,8 +452,8 @@ public void testGenericSetFactoryMethod() { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); } @Test @@ -474,8 +474,8 @@ public void testGenericSetListFactoryMethod() throws Exception { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); assertThat(gb.getResourceList().get(1)).isEqualTo(new UrlResource("http://localhost:9090")); } @@ -498,10 +498,10 @@ public void testGenericSetMapFactoryMethod() { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getIntegerSet().contains(new Integer(4))).isTrue(); - assertThat(gb.getIntegerSet().contains(new Integer(5))).isTrue(); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(new Integer(7)); + assertThat(gb.getIntegerSet().contains(4)).isTrue(); + assertThat(gb.getIntegerSet().contains(5)).isTrue(); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(7); } @Test @@ -519,8 +519,8 @@ public void testGenericMapResourceFactoryMethod() throws Exception { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(new Integer(7)); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(7); assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); } @@ -544,8 +544,8 @@ public void testGenericMapMapFactoryMethod() { assertThat(gb.getPlainMap().get("1")).isEqualTo("0"); assertThat(gb.getPlainMap().get("2")).isEqualTo("3"); - assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(new Integer(5)); - assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(new Integer(7)); + assertThat(gb.getShortMap().get(new Short("4"))).isEqualTo(5); + assertThat(gb.getShortMap().get(new Short("6"))).isEqualTo(7); } @Test @@ -580,7 +580,7 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { Map> input = new HashMap<>(); HashSet value1 = new HashSet<>(); - value1.add(new Integer(1)); + value1.add(1); input.put("1", value1); ArrayList value2 = new ArrayList<>(); value2.add(Boolean.TRUE); @@ -591,9 +591,9 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { bf.registerBeanDefinition("genericBean", rbd); GenericBean gb = (GenericBean) bf.getBean("genericBean"); - boolean condition1 = gb.getCollectionMap().get(new Integer(1)) instanceof HashSet; + boolean condition1 = gb.getCollectionMap().get(1) instanceof HashSet; assertThat(condition1).isTrue(); - boolean condition = gb.getCollectionMap().get(new Integer(2)) instanceof ArrayList; + boolean condition = gb.getCollectionMap().get(2) instanceof ArrayList; assertThat(condition).isTrue(); } @@ -624,7 +624,7 @@ public void testGenericMapBean() throws Exception { new ClassPathResource("genericBeanTests.xml", getClass())); Map map = (Map) bf.getBean("map"); assertThat(map.size()).isEqualTo(1); - assertThat(map.keySet().iterator().next()).isEqualTo(new Integer(10)); + assertThat(map.keySet().iterator().next()).isEqualTo(10); assertThat(map.values().iterator().next()).isEqualTo(new URL("http://localhost:8080")); } @@ -634,9 +634,9 @@ public void testGenericallyTypedIntegerBean() { new XmlBeanDefinitionReader(bf).loadBeanDefinitions( new ClassPathResource("genericBeanTests.xml", getClass())); GenericIntegerBean gb = (GenericIntegerBean) bf.getBean("integerBean"); - assertThat(gb.getGenericProperty()).isEqualTo(new Integer(10)); - assertThat(gb.getGenericListProperty().get(0)).isEqualTo(new Integer(20)); - assertThat(gb.getGenericListProperty().get(1)).isEqualTo(new Integer(30)); + assertThat(gb.getGenericProperty()).isEqualTo(10); + assertThat(gb.getGenericListProperty().get(0)).isEqualTo(20); + assertThat(gb.getGenericListProperty().get(1)).isEqualTo(30); } @Test @@ -645,9 +645,9 @@ public void testGenericallyTypedSetOfIntegerBean() { new XmlBeanDefinitionReader(bf).loadBeanDefinitions( new ClassPathResource("genericBeanTests.xml", getClass())); GenericSetOfIntegerBean gb = (GenericSetOfIntegerBean) bf.getBean("setOfIntegerBean"); - assertThat(gb.getGenericProperty().iterator().next()).isEqualTo(new Integer(10)); - assertThat(gb.getGenericListProperty().get(0).iterator().next()).isEqualTo(new Integer(20)); - assertThat(gb.getGenericListProperty().get(1).iterator().next()).isEqualTo(new Integer(30)); + assertThat(gb.getGenericProperty().iterator().next()).isEqualTo(10); + assertThat(gb.getGenericListProperty().get(0).iterator().next()).isEqualTo(20); + assertThat(gb.getGenericListProperty().get(1).iterator().next()).isEqualTo(30); } @Test diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistryTests.java index 303bc31ec4a9..6e3f8465e9e8 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistryTests.java @@ -20,8 +20,8 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.ObjectFactory; -import org.springframework.tests.sample.beans.DerivedTestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.DerivedTestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/DefinitionMetadataEqualsHashCodeTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/DefinitionMetadataEqualsHashCodeTests.java index ca09f9ee8464..36c0c4be39cc 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/DefinitionMetadataEqualsHashCodeTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/DefinitionMetadataEqualsHashCodeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; @@ -126,7 +126,7 @@ private void assertEqualsAndHashCodeContracts(Object master, Object equal, Objec assertThat(equal.hashCode()).as("Hash code for equal instances should match").isEqualTo(master.hashCode()); assertThat(notEqual).as("Should not be equal").isNotEqualTo(master); - assertThat(notEqual.hashCode()).as("Hash code for non-equal instances should not match").isNotEqualTo((long) master.hashCode()); + assertThat(notEqual.hashCode()).as("Hash code for non-equal instances should not match").isNotEqualTo(master.hashCode()); assertThat(subclass).as("Subclass should be equal").isEqualTo(master); assertThat(subclass.hashCode()).as("Hash code for subclass should match").isEqualTo(master.hashCode()); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/LookupMethodTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/LookupMethodTests.java index a12a21772b77..eeb34b6f8f1e 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/LookupMethodTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/LookupMethodTests.java @@ -20,8 +20,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReaderTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReaderTests.java index dd811aa41239..dbb70e54b9b0 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReaderTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReaderTests.java @@ -18,8 +18,8 @@ import org.junit.jupiter.api.Test; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java index 17fd92dd5ff4..f660a8af020d 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireBeanFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -244,7 +244,7 @@ public String getName() { @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Qualifier - private static @interface TestQualifier { + private @interface TestQualifier { } } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java index 8561abef9f87..84cb04da5994 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java @@ -45,7 +45,7 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.SmartFactoryBean; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.SecurityContextProvider; @@ -55,6 +55,7 @@ import org.springframework.core.NestedRuntimeException; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; +import org.springframework.core.testfixture.security.TestPrincipal; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -252,37 +253,6 @@ public String run() { }); } - private static class TestPrincipal implements Principal { - - private String name; - - public TestPrincipal(String name) { - this.name = name; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof TestPrincipal)) { - return false; - } - TestPrincipal p = (TestPrincipal) obj; - return this.name.equals(p.name); - } - - @Override - public int hashCode() { - return this.name.hashCode(); - } - } - public CallbacksSecurityTests() { // setup security if (System.getSecurityManager() == null) { @@ -442,7 +412,7 @@ public void testInitSecurityAwarePrototypeBean() { final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); BeanDefinitionBuilder bdb = BeanDefinitionBuilder .genericBeanDefinition(NonPrivilegedBean.class).setScope( - ConfigurableBeanFactory.SCOPE_PROTOTYPE) + BeanDefinition.SCOPE_PROTOTYPE) .setInitMethodName("init").setDestroyMethodName("destroy") .addConstructorArgValue("user1"); lbf.registerBeanDefinition("test", bdb.getBeanDefinition()); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/wiring/BeanConfigurerSupportTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/wiring/BeanConfigurerSupportTests.java index 8c5cb1e8b5c6..8ff2952fb113 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/wiring/BeanConfigurerSupportTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/wiring/BeanConfigurerSupportTests.java @@ -21,7 +21,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/AutowireWithExclusionTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/AutowireWithExclusionTests.java index 2ed794e57470..8ea0719a82be 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/AutowireWithExclusionTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/AutowireWithExclusionTests.java @@ -22,8 +22,8 @@ import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/CollectionMergingTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/CollectionMergingTests.java index 720bf605f38f..04b82ca200a8 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/CollectionMergingTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/CollectionMergingTests.java @@ -27,8 +27,8 @@ import org.springframework.beans.factory.support.BeanDefinitionReader; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/CollectionsWithDefaultTypesTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/CollectionsWithDefaultTypesTests.java index 1cdd84ba9fad..8a67fea2c1ba 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/CollectionsWithDefaultTypesTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/CollectionsWithDefaultTypesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; @@ -85,8 +85,8 @@ public void testBuildCollectionFromMixtureOfReferencesAndValues() throws Excepti List l = (List) jumble.getJumble(); assertThat(l.get(0).equals("literal")).isTrue(); Integer[] array1 = (Integer[]) l.get(1); - assertThat(array1[0].equals(new Integer(2))).isTrue(); - assertThat(array1[1].equals(new Integer(4))).isTrue(); + assertThat(array1[0].equals(2)).isTrue(); + assertThat(array1[1].equals(4)).isTrue(); int[] array2 = (int[]) l.get(2); assertThat(array2[0] == 3).isTrue(); assertThat(array2[1] == 5).isTrue(); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/ConstructorDependenciesBean.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/ConstructorDependenciesBean.java index f4ca864f830e..1d3c6286d312 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/ConstructorDependenciesBean.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/ConstructorDependenciesBean.java @@ -18,8 +18,8 @@ import java.io.Serializable; -import org.springframework.tests.sample.beans.IndexedTestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.IndexedTestBean; +import org.springframework.beans.testfixture.beans.TestBean; /** * Simple bean used to check constructor dependency checking. diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/CountingFactory.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/CountingFactory.java index 3a992e3334ba..21ccf619b38b 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/CountingFactory.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/CountingFactory.java @@ -17,7 +17,7 @@ package org.springframework.beans.factory.xml; import org.springframework.beans.factory.FactoryBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; /** * @author Juergen Hoeller diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/DummyReferencer.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/DummyReferencer.java index 352e08958048..10bf54f5e07c 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/DummyReferencer.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/DummyReferencer.java @@ -17,8 +17,8 @@ package org.springframework.beans.factory.xml; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.tests.sample.beans.factory.DummyFactory; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.beans.testfixture.beans.factory.DummyFactory; /** * @author Juergen Hoeller diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests.java index 983292c56aad..2520004ea3c6 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests.java @@ -19,8 +19,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/EventPublicationTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/EventPublicationTests.java index 7fef2df708e3..29e2561fc756 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/EventPublicationTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/EventPublicationTests.java @@ -30,8 +30,8 @@ import org.springframework.beans.factory.parsing.ImportDefinition; import org.springframework.beans.factory.parsing.PassThroughSourceExtractor; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.CollectingReaderEventListener; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.beans.CollectingReaderEventListener; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java index 3985567eb54c..d2f26ee0fe63 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,9 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.FactoryMethods; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -287,7 +288,7 @@ public void testCanSpecifyFactoryMethodArgumentsOnFactoryMethodPrototype() { assertThat(fm2.getTestBean()).isSameAs(fm2.getTestBean()); assertThat(fm2).isNotSameAs(fm1); - FactoryMethods fm3 = (FactoryMethods) xbf.getBean("testBeanOnlyPrototype", tbArg2, new Integer(1), "myName"); + FactoryMethods fm3 = (FactoryMethods) xbf.getBean("testBeanOnlyPrototype", tbArg2, 1, "myName"); assertThat(fm3.getNum()).isEqualTo(1); assertThat(fm3.getName()).isEqualTo("myName"); assertThat(fm3.getTestBean().getName()).isEqualTo("arg2"); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/InstanceFactory.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/InstanceFactory.java index 8cf0fa91099c..af7f2f718b19 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/InstanceFactory.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/InstanceFactory.java @@ -16,7 +16,8 @@ package org.springframework.beans.factory.xml; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.FactoryMethods; +import org.springframework.beans.testfixture.beans.TestBean; /** * Test class for Spring's ability to create objects using diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests.java index 6934e5166bc2..debeb353cafa 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests.java @@ -20,8 +20,8 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/SchemaValidationTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/SchemaValidationTests.java index 1d51dc3f0bb1..70199450995b 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/SchemaValidationTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/SchemaValidationTests.java @@ -21,8 +21,8 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/SimpleConstructorNamespaceHandlerTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/SimpleConstructorNamespaceHandlerTests.java index 0d4921e4138d..24a9d43e89be 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/SimpleConstructorNamespaceHandlerTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/SimpleConstructorNamespaceHandlerTests.java @@ -20,9 +20,9 @@ import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.DummyBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.DummyBean; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/SimplePropertyNamespaceHandlerTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/SimplePropertyNamespaceHandlerTests.java index b8f943fccd22..68ef31d9a82f 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/SimplePropertyNamespaceHandlerTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/SimplePropertyNamespaceHandlerTests.java @@ -20,9 +20,9 @@ import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/TestBeanCreator.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/TestBeanCreator.java index adee655ad494..091a20290e7c 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/TestBeanCreator.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/TestBeanCreator.java @@ -16,7 +16,7 @@ package org.springframework.beans.factory.xml; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; /** * Test class for Spring's ability to create diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/UtilNamespaceHandlerTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/UtilNamespaceHandlerTests.java index be6be77551c5..2260a86c52e9 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/UtilNamespaceHandlerTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/UtilNamespaceHandlerTests.java @@ -32,10 +32,10 @@ import org.springframework.beans.factory.parsing.ComponentDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.CollectingReaderEventListener; +import org.springframework.beans.testfixture.beans.CustomEnum; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.beans.CollectingReaderEventListener; -import org.springframework.tests.sample.beans.CustomEnum; -import org.springframework.tests.sample.beans.TestBean; import org.springframework.util.LinkedCaseInsensitiveMap; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanCollectionTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanCollectionTests.java index 17eadf0c61dc..e44f0d9df7a0 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanCollectionTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanCollectionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,9 +38,9 @@ import org.springframework.beans.factory.config.MapFactoryBean; import org.springframework.beans.factory.config.SetFactoryBean; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.testfixture.beans.HasMap; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.HasMap; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -201,16 +201,16 @@ public void testMapWithLiteralsOnly() throws Exception { public void testMapWithLiteralsAndReferences() throws Exception { HasMap hasMap = (HasMap) this.beanFactory.getBean("mixedMap"); assertThat(hasMap.getMap().size() == 5).isTrue(); - assertThat(hasMap.getMap().get("foo").equals(new Integer(10))).isTrue(); + assertThat(hasMap.getMap().get("foo").equals(10)).isTrue(); TestBean jenny = (TestBean) this.beanFactory.getBean("jenny"); assertThat(hasMap.getMap().get("jenny") == jenny).isTrue(); - assertThat(hasMap.getMap().get(new Integer(5)).equals("david")).isTrue(); + assertThat(hasMap.getMap().get(5).equals("david")).isTrue(); boolean condition1 = hasMap.getMap().get("bar") instanceof Long; assertThat(condition1).isTrue(); - assertThat(hasMap.getMap().get("bar").equals(new Long(100))).isTrue(); + assertThat(hasMap.getMap().get("bar").equals(100L)).isTrue(); boolean condition = hasMap.getMap().get("baz") instanceof Integer; assertThat(condition).isTrue(); - assertThat(hasMap.getMap().get("baz").equals(new Integer(200))).isTrue(); + assertThat(hasMap.getMap().get("baz").equals(200)).isTrue(); } @Test diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java index 9b460c6601af..69768da8278f 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReaderTests.java @@ -25,10 +25,10 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; -import org.springframework.tests.sample.beans.TestBean; import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java index d0b83d98155a..d48b55f2cb8d 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java @@ -30,11 +30,12 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.LifecycleBean; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.beans.testfixture.beans.factory.DummyFactory; +import org.springframework.beans.testfixture.factory.xml.AbstractListableBeanFactoryTests; import org.springframework.core.io.ClassPathResource; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.LifecycleBean; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.tests.sample.beans.factory.DummyFactory; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/BeanInfoTests.java b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/BeanInfoTests.java index b08587fa6ea5..7b91fc60e64a 100644 --- a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/BeanInfoTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/BeanInfoTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,12 +39,12 @@ public class BeanInfoTests { public void testComplexObject() { ValueBean bean = new ValueBean(); BeanWrapper bw = new BeanWrapperImpl(bean); - Integer value = new Integer(1); + Integer value = 1; bw.setPropertyValue("value", value); assertThat(value).as("value not set correctly").isEqualTo(bean.getValue()); - value = new Integer(2); + value = 2; bw.setPropertyValue("value", value.toString()); assertThat(value).as("value not converted").isEqualTo(bean.getValue()); diff --git a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/CustomCollectionEditorTests.java b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/CustomCollectionEditorTests.java index 36fd15b997dd..ad8d4c761de2 100644 --- a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/CustomCollectionEditorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/CustomCollectionEditorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,9 +63,9 @@ public void testSunnyDaySetValue() throws Exception { assertThat(condition).isTrue(); List list = (List) value; assertThat(list.size()).as("There must be 3 elements in the converted collection").isEqualTo(3); - assertThat(list.get(0)).isEqualTo(new Integer(0)); - assertThat(list.get(1)).isEqualTo(new Integer(1)); - assertThat(list.get(2)).isEqualTo(new Integer(2)); + assertThat(list.get(0)).isEqualTo(0); + assertThat(list.get(1)).isEqualTo(1); + assertThat(list.get(2)).isEqualTo(2); } @Test diff --git a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/CustomEditorTests.java b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/CustomEditorTests.java index 85bf11b9d619..0de98a10f002 100644 --- a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/CustomEditorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/CustomEditorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,11 +43,11 @@ import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; -import org.springframework.tests.sample.beans.BooleanTestBean; -import org.springframework.tests.sample.beans.ITestBean; -import org.springframework.tests.sample.beans.IndexedTestBean; -import org.springframework.tests.sample.beans.NumberTestBean; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.BooleanTestBean; +import org.springframework.beans.testfixture.beans.ITestBean; +import org.springframework.beans.testfixture.beans.IndexedTestBean; +import org.springframework.beans.testfixture.beans.NumberTestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -75,7 +75,7 @@ public void testComplexObject() { BeanWrapper bw = new BeanWrapperImpl(tb); bw.registerCustomEditor(ITestBean.class, new TestBeanEditor()); MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.addPropertyValue(new PropertyValue("age", new Integer(55))); + pvs.addPropertyValue(new PropertyValue("age", 55)); pvs.addPropertyValue(new PropertyValue("name", newName)); pvs.addPropertyValue(new PropertyValue("touchy", "valid")); pvs.addPropertyValue(new PropertyValue("spouse", tbString)); @@ -94,7 +94,7 @@ public void testComplexObjectWithOldValueAccess() { bw.setExtractOldValueForEditor(true); bw.registerCustomEditor(ITestBean.class, new OldValueAccessingTestBeanEditor()); MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.addPropertyValue(new PropertyValue("age", new Integer(55))); + pvs.addPropertyValue(new PropertyValue("age", 55)); pvs.addPropertyValue(new PropertyValue("name", newName)); pvs.addPropertyValue(new PropertyValue("touchy", "valid")); pvs.addPropertyValue(new PropertyValue("spouse", tbString)); @@ -593,9 +593,9 @@ public void testClassEditorWithNonExistentClass() throws Exception { @Test public void testClassEditorWithArray() { PropertyEditor classEditor = new ClassEditor(); - classEditor.setAsText("org.springframework.tests.sample.beans.TestBean[]"); + classEditor.setAsText("org.springframework.beans.testfixture.beans.TestBean[]"); assertThat(classEditor.getValue()).isEqualTo(TestBean[].class); - assertThat(classEditor.getAsText()).isEqualTo("org.springframework.tests.sample.beans.TestBean[]"); + assertThat(classEditor.getAsText()).isEqualTo("org.springframework.beans.testfixture.beans.TestBean[]"); } /* @@ -756,7 +756,7 @@ public void testCustomDateEditorWithExactDateLength() { public void testCustomNumberEditor() { CustomNumberEditor editor = new CustomNumberEditor(Integer.class, false); editor.setAsText("5"); - assertThat(editor.getValue()).isEqualTo(new Integer(5)); + assertThat(editor.getValue()).isEqualTo(5); assertThat(editor.getAsText()).isEqualTo("5"); editor.setValue(null); assertThat(editor.getValue()).isEqualTo(null); @@ -767,14 +767,14 @@ public void testCustomNumberEditor() { public void testCustomNumberEditorWithHex() { CustomNumberEditor editor = new CustomNumberEditor(Integer.class, false); editor.setAsText("0x" + Integer.toHexString(64)); - assertThat(editor.getValue()).isEqualTo(new Integer(64)); + assertThat(editor.getValue()).isEqualTo(64); } @Test public void testCustomNumberEditorWithEmptyAsNull() { CustomNumberEditor editor = new CustomNumberEditor(Integer.class, true); editor.setAsText("5"); - assertThat(editor.getValue()).isEqualTo(new Integer(5)); + assertThat(editor.getValue()).isEqualTo(5); assertThat(editor.getAsText()).isEqualTo("5"); editor.setAsText(""); assertThat(editor.getValue()).isEqualTo(null); diff --git a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/PathEditorTests.java b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/PathEditorTests.java index 40354fc44643..f0c659bcbdb7 100644 --- a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/PathEditorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/PathEditorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,57 +34,78 @@ public class PathEditorTests { @Test - public void testClasspathPathName() throws Exception { + public void testClasspathPathName() { PropertyEditor pathEditor = new PathEditor(); pathEditor.setAsText("classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + ".class"); Object value = pathEditor.getValue(); - boolean condition = value instanceof Path; - assertThat(condition).isTrue(); + assertThat(value instanceof Path).isTrue(); Path path = (Path) value; assertThat(path.toFile().exists()).isTrue(); } @Test - public void testWithNonExistentResource() throws Exception { + public void testWithNonExistentResource() { PropertyEditor propertyEditor = new PathEditor(); assertThatIllegalArgumentException().isThrownBy(() -> propertyEditor.setAsText("classpath:/no_way_this_file_is_found.doc")); } @Test - public void testWithNonExistentPath() throws Exception { + public void testWithNonExistentPath() { PropertyEditor pathEditor = new PathEditor(); pathEditor.setAsText("file:/no_way_this_file_is_found.doc"); Object value = pathEditor.getValue(); - boolean condition1 = value instanceof Path; - assertThat(condition1).isTrue(); + assertThat(value instanceof Path).isTrue(); Path path = (Path) value; - boolean condition = !path.toFile().exists(); - assertThat(condition).isTrue(); + assertThat(!path.toFile().exists()).isTrue(); } @Test - public void testAbsolutePath() throws Exception { + public void testAbsolutePath() { PropertyEditor pathEditor = new PathEditor(); pathEditor.setAsText("/no_way_this_file_is_found.doc"); Object value = pathEditor.getValue(); - boolean condition1 = value instanceof Path; - assertThat(condition1).isTrue(); + assertThat(value instanceof Path).isTrue(); Path path = (Path) value; - boolean condition = !path.toFile().exists(); - assertThat(condition).isTrue(); + assertThat(!path.toFile().exists()).isTrue(); } @Test - public void testUnqualifiedPathNameFound() throws Exception { + public void testWindowsAbsolutePath() { + PropertyEditor pathEditor = new PathEditor(); + pathEditor.setAsText("C:\\no_way_this_file_is_found.doc"); + Object value = pathEditor.getValue(); + assertThat(value instanceof Path).isTrue(); + Path path = (Path) value; + assertThat(!path.toFile().exists()).isTrue(); + } + + @Test + public void testWindowsAbsoluteFilePath() { + PropertyEditor pathEditor = new PathEditor(); + try { + pathEditor.setAsText("file://C:\\no_way_this_file_is_found.doc"); + Object value = pathEditor.getValue(); + assertThat(value instanceof Path).isTrue(); + Path path = (Path) value; + assertThat(!path.toFile().exists()).isTrue(); + } + catch (IllegalArgumentException ex) { + if (File.separatorChar == '\\') { // on Windows, otherwise silently ignore + throw ex; + } + } + } + + @Test + public void testUnqualifiedPathNameFound() { PropertyEditor pathEditor = new PathEditor(); String fileName = ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + ".class"; pathEditor.setAsText(fileName); Object value = pathEditor.getValue(); - boolean condition = value instanceof Path; - assertThat(condition).isTrue(); + assertThat(value instanceof Path).isTrue(); Path path = (Path) value; File file = path.toFile(); assertThat(file.exists()).isTrue(); @@ -96,14 +117,13 @@ public void testUnqualifiedPathNameFound() throws Exception { } @Test - public void testUnqualifiedPathNameNotFound() throws Exception { + public void testUnqualifiedPathNameNotFound() { PropertyEditor pathEditor = new PathEditor(); String fileName = ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + ".clazz"; pathEditor.setAsText(fileName); Object value = pathEditor.getValue(); - boolean condition = value instanceof Path; - assertThat(condition).isTrue(); + assertThat(value instanceof Path).isTrue(); Path path = (Path) value; File file = path.toFile(); assertThat(file.exists()).isFalse(); diff --git a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditorTests.java b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditorTests.java index 09716d04fd08..0583c78460b7 100644 --- a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditorTests.java @@ -23,39 +23,31 @@ /** * @author Rick Evans * @author Juergen Hoeller + * @author Sam Brannen */ -public class StringArrayPropertyEditorTests { +class StringArrayPropertyEditorTests { @Test - public void withDefaultSeparator() throws Exception { + void withDefaultSeparator() { StringArrayPropertyEditor editor = new StringArrayPropertyEditor(); editor.setAsText("0,1,2"); Object value = editor.getValue(); - assertThat(value).isNotNull(); - boolean condition = value instanceof String[]; - assertThat(condition).isTrue(); - String[] array = (String[]) value; - for (int i = 0; i < array.length; ++i) { - assertThat(array[i]).isEqualTo(("" + i)); - } + assertTrimmedElements(value); assertThat(editor.getAsText()).isEqualTo("0,1,2"); } @Test - public void trimByDefault() throws Exception { + void trimByDefault() { StringArrayPropertyEditor editor = new StringArrayPropertyEditor(); editor.setAsText(" 0,1 , 2 "); Object value = editor.getValue(); - String[] array = (String[]) value; - for (int i = 0; i < array.length; ++i) { - assertThat(array[i]).isEqualTo(("" + i)); - } + assertTrimmedElements(value); assertThat(editor.getAsText()).isEqualTo("0,1,2"); } @Test - public void noTrim() throws Exception { - StringArrayPropertyEditor editor = new StringArrayPropertyEditor(",",false,false); + void noTrim() { + StringArrayPropertyEditor editor = new StringArrayPropertyEditor(",", false, false); editor.setAsText(" 0,1 , 2 "); Object value = editor.getValue(); String[] array = (String[]) value; @@ -67,48 +59,45 @@ public void noTrim() throws Exception { } @Test - public void withCustomSeparator() throws Exception { + void withCustomSeparator() { StringArrayPropertyEditor editor = new StringArrayPropertyEditor(":"); editor.setAsText("0:1:2"); Object value = editor.getValue(); - boolean condition = value instanceof String[]; - assertThat(condition).isTrue(); - String[] array = (String[]) value; - for (int i = 0; i < array.length; ++i) { - assertThat(array[i]).isEqualTo(("" + i)); - } + assertTrimmedElements(value); assertThat(editor.getAsText()).isEqualTo("0:1:2"); } @Test - public void withCharsToDelete() throws Exception { + void withCharsToDelete() { StringArrayPropertyEditor editor = new StringArrayPropertyEditor(",", "\r\n", false); editor.setAsText("0\r,1,\n2"); Object value = editor.getValue(); - boolean condition = value instanceof String[]; - assertThat(condition).isTrue(); - String[] array = (String[]) value; - for (int i = 0; i < array.length; ++i) { - assertThat(array[i]).isEqualTo(("" + i)); - } + assertTrimmedElements(value); assertThat(editor.getAsText()).isEqualTo("0,1,2"); } @Test - public void withEmptyArray() throws Exception { + void withEmptyArray() { StringArrayPropertyEditor editor = new StringArrayPropertyEditor(); editor.setAsText(""); Object value = editor.getValue(); - boolean condition = value instanceof String[]; - assertThat(condition).isTrue(); - assertThat(((String[]) value).length).isEqualTo(0); + assertThat(value).isInstanceOf(String[].class); + assertThat((String[]) value).isEmpty(); } @Test - public void withEmptyArrayAsNull() throws Exception { + void withEmptyArrayAsNull() { StringArrayPropertyEditor editor = new StringArrayPropertyEditor(",", true); editor.setAsText(""); assertThat(editor.getValue()).isNull(); } + private static void assertTrimmedElements(Object value) { + assertThat(value).isInstanceOf(String[].class); + String[] array = (String[]) value; + for (int i = 0; i < array.length; ++i) { + assertThat(array[i]).isEqualTo(("" + i)); + } + } + } diff --git a/spring-beans/src/test/java/org/springframework/beans/support/PagedListHolderTests.java b/spring-beans/src/test/java/org/springframework/beans/support/PagedListHolderTests.java index 74a8769d7044..0afce6483444 100644 --- a/spring-beans/src/test/java/org/springframework/beans/support/PagedListHolderTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/support/PagedListHolderTests.java @@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-beans/src/test/kotlin/org/springframework/beans/KotlinBeanUtilsTests.kt b/spring-beans/src/test/kotlin/org/springframework/beans/KotlinBeanUtilsTests.kt index 948292bd8386..647d320fad96 100644 --- a/spring-beans/src/test/kotlin/org/springframework/beans/KotlinBeanUtilsTests.kt +++ b/spring-beans/src/test/kotlin/org/springframework/beans/KotlinBeanUtilsTests.kt @@ -74,6 +74,22 @@ class KotlinBeanUtilsTests { assertThat(baz.param2).isEqualTo(12) } + @Test + @Suppress("UsePropertyAccessSyntax") + fun `Instantiate class with private constructor`() { + BeanUtils.instantiateClass(PrivateConstructor::class.java.getDeclaredConstructor()) + } + + @Test + fun `Instantiate class with protected constructor`() { + BeanUtils.instantiateClass(ProtectedConstructor::class.java.getDeclaredConstructor()) + } + + @Test + fun `Instantiate private class`() { + BeanUtils.instantiateClass(PrivateClass::class.java.getDeclaredConstructor()) + } + class Foo(val param1: String, val param2: Int) class Bar(val param1: String, val param2: Int = 12) @@ -106,4 +122,10 @@ class KotlinBeanUtilsTests { constructor(param1: String) } + class PrivateConstructor private constructor() + + open class ProtectedConstructor protected constructor() + + private class PrivateClass + } diff --git a/spring-beans/src/test/kotlin/org/springframework/beans/factory/annotation/KotlinAutowiredTests.kt b/spring-beans/src/test/kotlin/org/springframework/beans/factory/annotation/KotlinAutowiredTests.kt index a254900fa36b..37d6793cad50 100644 --- a/spring-beans/src/test/kotlin/org/springframework/beans/factory/annotation/KotlinAutowiredTests.kt +++ b/spring-beans/src/test/kotlin/org/springframework/beans/factory/annotation/KotlinAutowiredTests.kt @@ -22,8 +22,8 @@ import org.junit.jupiter.api.Test import org.springframework.beans.factory.BeanCreationException import org.springframework.beans.factory.support.DefaultListableBeanFactory import org.springframework.beans.factory.support.RootBeanDefinition -import org.springframework.tests.sample.beans.Colour -import org.springframework.tests.sample.beans.TestBean +import org.springframework.beans.testfixture.beans.Colour +import org.springframework.beans.testfixture.beans.TestBean /** * Tests for Kotlin support with [Autowired]. diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-leaf.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-leaf.xml index e9abc664d662..435dcb06cbd8 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-leaf.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-leaf.xml @@ -3,7 +3,7 @@ - + custom 25 diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-middle.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-middle.xml index 4807313fed67..4804e44cf889 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-middle.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-middle.xml @@ -4,7 +4,7 @@ - + custom 666 @@ -13,7 +13,7 @@ Check that invoker is automatically added to wrap target. Non pointcut bean name should be wrapped in invoker. --> - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-root.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-root.xml index 26560b27fb4c..fea62a3791b1 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-root.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/BeanFactoryUtilsTests-root.xml @@ -6,21 +6,21 @@ - + - + - + - + custom 25 - + - + false diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests-context.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests-context.xml index c14569c7fa57..35c854bdb0e0 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests-context.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/config/FieldRetrievingFactoryBeanTests-context.xml @@ -3,7 +3,7 @@ - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests-context.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests-context.xml index dbcea8f953b0..d9979e38339a 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests-context.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests-context.xml @@ -3,19 +3,19 @@ - + 10 - + 11 - + 98 - + 99 @@ -23,7 +23,7 @@ - + 12 @@ -46,10 +46,10 @@ tb spouse - org.springframework.tests.sample.beans.TestBean + org.springframework.beans.testfixture.beans.TestBean - + @@ -59,11 +59,11 @@ - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/config/SimpleScopeTests-context.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/config/SimpleScopeTests-context.xml index 5a180e701381..9ac321b0cc45 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/config/SimpleScopeTests-context.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/config/SimpleScopeTests-context.xml @@ -3,6 +3,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/parsing/CustomProblemReporterTests-context.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/parsing/CustomProblemReporterTests-context.xml index 12b096820436..1c6e22b51182 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/parsing/CustomProblemReporterTests-context.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/parsing/CustomProblemReporterTests-context.xml @@ -6,7 +6,7 @@ - + @@ -14,9 +14,9 @@ - + - + @@ -26,5 +26,6 @@ - + + \ No newline at end of file diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/support/genericBeanTests.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/support/genericBeanTests.xml index c8a0ab7549d7..c610f9cf1591 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/support/genericBeanTests.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/support/genericBeanTests.xml @@ -3,7 +3,7 @@ - + @@ -43,7 +43,7 @@ autowire="constructor"> - + @@ -53,7 +53,7 @@ - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/support/lookupMethodTests.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/support/lookupMethodTests.xml index 1334415c7460..a04f0e3beb42 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/support/lookupMethodTests.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/support/lookupMethodTests.xml @@ -13,9 +13,9 @@ - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/support/multiConstructorArgs.properties b/spring-beans/src/test/resources/org/springframework/beans/factory/support/multiConstructorArgs.properties index 8d5f74fc31a9..9cc82ac44933 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/support/multiConstructorArgs.properties +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/support/multiConstructorArgs.properties @@ -1,3 +1,3 @@ -testBean.(class)=org.springframework.tests.sample.beans.TestBean +testBean.(class)=org.springframework.beans.testfixture.beans.TestBean testBean.$0=Rob Harrop testBean.$1=23 diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/support/refConstructorArg.properties b/spring-beans/src/test/resources/org/springframework/beans/factory/support/refConstructorArg.properties index 4d3723c7de8a..b1bb01e2a507 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/support/refConstructorArg.properties +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/support/refConstructorArg.properties @@ -1,5 +1,5 @@ -sally.(class)=org.springframework.tests.sample.beans.TestBean +sally.(class)=org.springframework.beans.testfixture.beans.TestBean sally.name=Sally -rob.(class)=org.springframework.tests.sample.beans.TestBean +rob.(class)=org.springframework.beans.testfixture.beans.TestBean rob.$0(ref)=sally diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/support/simpleConstructorArg.properties b/spring-beans/src/test/resources/org/springframework/beans/factory/support/simpleConstructorArg.properties index d0f1eea32665..bc39b1b018c0 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/support/simpleConstructorArg.properties +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/support/simpleConstructorArg.properties @@ -1,2 +1,2 @@ -testBean.(class)=org.springframework.tests.sample.beans.TestBean +testBean.(class)=org.springframework.beans.testfixture.beans.TestBean testBean.$0=Rob Harrop diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/DuplicateBeanIdTests-multiLevel-context.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/DuplicateBeanIdTests-multiLevel-context.xml index f5f975bf7b51..0e326790f7fd 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/DuplicateBeanIdTests-multiLevel-context.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/DuplicateBeanIdTests-multiLevel-context.xml @@ -4,12 +4,12 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/DuplicateBeanIdTests-sameLevel-context.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/DuplicateBeanIdTests-sameLevel-context.xml index 7bd11a987175..40ecbec4ac9a 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/DuplicateBeanIdTests-sameLevel-context.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/DuplicateBeanIdTests-sameLevel-context.xml @@ -4,12 +4,12 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-merge-context.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-merge-context.xml index 55a5cf04e7fe..f3453c7bb943 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-merge-context.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-merge-context.xml @@ -5,7 +5,7 @@ https://www.springframework.org/schema/beans/spring-beans-3.1.xsd" default-merge="false"> - + alpha diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-constructor-with-exclusion.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-constructor-with-exclusion.xml index 0b67be5d8748..2b2515103095 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-constructor-with-exclusion.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-constructor-with-exclusion.xml @@ -3,9 +3,9 @@ - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-exclusion.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-exclusion.xml index 37a98d0ce810..692cc7743f56 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-exclusion.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-exclusion.xml @@ -3,9 +3,9 @@ - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-inclusion.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-inclusion.xml index b47d4231ce0c..f4090d14a71e 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-inclusion.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-inclusion.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd" default-autowire-candidates=""> - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-selective-inclusion.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-selective-inclusion.xml index 5df4f9c21dca..d52ba19ec021 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-selective-inclusion.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/autowire-with-selective-inclusion.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd" default-autowire-candidates="props*,*ly"> - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/beanEvents.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/beanEvents.xml index 9b019ee2ff2a..2bdea186844c 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/beanEvents.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/beanEvents.xml @@ -10,22 +10,22 @@ - + - + - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collectionMerging.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collectionMerging.xml index b3a6142b54fa..d45764707947 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collectionMerging.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collectionMerging.xml @@ -3,7 +3,7 @@ - + Rob Harrop @@ -23,12 +23,12 @@ - + - + Rob Harrop @@ -47,14 +47,14 @@ - + - + @@ -76,7 +76,7 @@ - + @@ -84,7 +84,7 @@ - + Sall @@ -103,7 +103,7 @@ - + Rob Harrop @@ -123,12 +123,12 @@ - + - + Rob Harrop @@ -147,14 +147,14 @@ - + - + @@ -176,7 +176,7 @@ - + @@ -184,7 +184,7 @@ - + Sall diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collections.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collections.xml index 0f2fff8c9b91..5683b4fe490e 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collections.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collections.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> - + Jenny 30 @@ -12,7 +12,7 @@ - + Simple bean, without any collections. @@ -23,7 +23,7 @@ 27 - + Rod 32 @@ -35,7 +35,7 @@ - + Jenny 30 @@ -43,13 +43,13 @@ - + David 27 - + Rod 32 @@ -63,7 +63,7 @@ - + loner 26 @@ -101,26 +101,26 @@ - + verbose - + - + - + - + @@ -130,7 +130,7 @@ - + @@ -157,7 +157,7 @@ - + @@ -176,7 +176,7 @@ - + @@ -185,7 +185,7 @@ - + @@ -217,14 +217,14 @@ - + - + bar @@ -234,7 +234,7 @@ - + bar @@ -244,7 +244,7 @@ - + @@ -253,7 +253,7 @@ - + @@ -261,7 +261,7 @@ - + bar @@ -270,7 +270,7 @@ - + @@ -279,7 +279,7 @@ - + one @@ -288,7 +288,7 @@ - + 0 @@ -298,11 +298,11 @@ - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collectionsWithDefaultTypes.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collectionsWithDefaultTypes.xml index 92d5d3db1dbd..a1a1ea378b1b 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collectionsWithDefaultTypes.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/collectionsWithDefaultTypes.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> - + 1 @@ -28,7 +28,7 @@ - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/factory-methods.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/factory-methods.xml index 86d94732956d..93f338b00178 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/factory-methods.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/factory-methods.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> - setterString @@ -21,48 +21,48 @@ - - - setterString - 27 gotcha - 27 - 27 - 27 - @@ -72,31 +72,31 @@ - setterString - testBeanOnlyPrototypeDISetterString - - 27 gotcha - 27 @@ -104,10 +104,10 @@ bogus - - + Juergen @@ -130,7 +130,7 @@ - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/schemaValidated.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/schemaValidated.xml index 5f22ea3cef42..59b5ef71c3cc 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/schemaValidated.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/schemaValidated.xml @@ -3,16 +3,16 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> - + - + - + - - + + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simpleConstructorNamespaceHandlerTests.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simpleConstructorNamespaceHandlerTests.xml index 0c6b70e59ac5..c8adc6bdb3dc 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simpleConstructorNamespaceHandlerTests.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simpleConstructorNamespaceHandlerTests.xml @@ -5,43 +5,43 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + - + - + - + - + - + - + \ No newline at end of file diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simpleConstructorNamespaceHandlerTestsWithErrors.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simpleConstructorNamespaceHandlerTestsWithErrors.xml index 932492e9d14c..3dbfb5fae18f 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simpleConstructorNamespaceHandlerTestsWithErrors.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simpleConstructorNamespaceHandlerTestsWithErrors.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simplePropertyNamespaceHandlerTests.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simplePropertyNamespaceHandlerTests.xml index 7b62d39e2792..83e74fad1694 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simplePropertyNamespaceHandlerTests.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simplePropertyNamespaceHandlerTests.xml @@ -4,20 +4,20 @@ xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + - + - + - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simplePropertyNamespaceHandlerTestsWithErrors.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simplePropertyNamespaceHandlerTestsWithErrors.xml index c0335508acc8..b64093d0fc8a 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simplePropertyNamespaceHandlerTestsWithErrors.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/simplePropertyNamespaceHandlerTestsWithErrors.xml @@ -4,10 +4,10 @@ xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/test.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/test.xml index 3a0b944bef3c..7c4c7596e79f 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/test.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/test.xml @@ -3,7 +3,7 @@ - + I have no properties and I'm happy without them. @@ -12,7 +12,7 @@ - + aliased @@ -20,17 +20,17 @@ - + aliased - + aliased - + @@ -40,7 +40,7 @@ - + Rod 31 @@ -52,29 +52,29 @@ - + Kerry 34 - + Kathy 28 - + typeMismatch 34x - + - true @@ -85,10 +85,10 @@ - + - + false @@ -113,14 +113,14 @@ - + listenerVeto 66 - + - + this is a ]]> diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/testUtilNamespace.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/testUtilNamespace.xml index b2bad9b4c515..972aabcd669a 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/testUtilNamespace.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/testUtilNamespace.xml @@ -17,7 +17,7 @@ name "/> - + @@ -26,13 +26,13 @@ - + - + @@ -50,7 +50,7 @@ + key-type="java.lang.String" value-type="org.springframework.beans.testfixture.beans.TestBean"> @@ -72,7 +72,7 @@ Rob Harrop - + foo @@ -94,13 +94,13 @@ - + - + @@ -116,13 +116,13 @@ min - + - + @@ -152,7 +152,7 @@ - + diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/validateWithDtd.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/validateWithDtd.xml index a872ae9d23d7..fbe7861e21c0 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/validateWithDtd.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/validateWithDtd.xml @@ -9,5 +9,5 @@ This is a top level block comment - + \ No newline at end of file diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/validateWithXsd.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/validateWithXsd.xml index c7e8abe5a55b..1e467348ea18 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/validateWithXsd.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/validateWithXsd.xml @@ -7,5 +7,5 @@ This is a top level block comment the parser now --> - + \ No newline at end of file diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/withMeta.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/withMeta.xml index 5126d253957b..5f7388177722 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/withMeta.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/withMeta.xml @@ -4,15 +4,15 @@ xmlns:spring="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> - + - + - + diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/AgeHolder.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/AgeHolder.java similarity index 93% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/AgeHolder.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/AgeHolder.java index adced8acea9a..722cea949646 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/AgeHolder.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/AgeHolder.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; public interface AgeHolder { diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/AnnotatedBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/AnnotatedBean.java similarity index 93% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/AnnotatedBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/AnnotatedBean.java index 6b4e063563bd..985cf64de8af 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/AnnotatedBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/AnnotatedBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * @author Stephane Nicoll diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/BooleanTestBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/BooleanTestBean.java similarity index 95% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/BooleanTestBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/BooleanTestBean.java index bf6105ca55f6..5edbd304eddc 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/BooleanTestBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/BooleanTestBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * @author Juergen Hoeller diff --git a/spring-beans/src/test/java/org/springframework/tests/beans/CollectingReaderEventListener.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/CollectingReaderEventListener.java similarity index 88% rename from spring-beans/src/test/java/org/springframework/tests/beans/CollectingReaderEventListener.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/CollectingReaderEventListener.java index c46e59c3665a..a4684998a36a 100644 --- a/spring-beans/src/test/java/org/springframework/tests/beans/CollectingReaderEventListener.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/CollectingReaderEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.beans; +package org.springframework.beans.testfixture.beans; import java.util.ArrayList; import java.util.Collection; @@ -65,16 +65,12 @@ public ComponentDefinition getComponentDefinition(String name) { public ComponentDefinition[] getComponentDefinitions() { Collection collection = this.componentDefinitions.values(); - return collection.toArray(new ComponentDefinition[collection.size()]); + return collection.toArray(new ComponentDefinition[0]); } @Override public void aliasRegistered(AliasDefinition aliasDefinition) { - List aliases = this.aliasMap.get(aliasDefinition.getBeanName()); - if (aliases == null) { - aliases = new ArrayList<>(); - this.aliasMap.put(aliasDefinition.getBeanName(), aliases); - } + List aliases = this.aliasMap.computeIfAbsent(aliasDefinition.getBeanName(), k -> new ArrayList<>()); aliases.add(aliasDefinition); } diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/Colour.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Colour.java similarity index 95% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/Colour.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Colour.java index a1910a9dfa41..531149005197 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/Colour.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Colour.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * @author Rob Harrop diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/CountingTestBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/CountingTestBean.java similarity index 93% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/CountingTestBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/CountingTestBean.java index 74faeba68b85..aa9083a88e11 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/CountingTestBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/CountingTestBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/CustomEnum.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/CustomEnum.java similarity index 93% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/CustomEnum.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/CustomEnum.java index dec612088da0..de0d721943d8 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/CustomEnum.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/CustomEnum.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * @author Juergen Hoeller diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/DependenciesBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DependenciesBean.java similarity index 96% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/DependenciesBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DependenciesBean.java index 4f0e958c7f74..f990781e11df 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/DependenciesBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DependenciesBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/DerivedTestBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DerivedTestBean.java similarity index 97% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/DerivedTestBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DerivedTestBean.java index 92c62dd5da87..c0e9c2e1dca4 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/DerivedTestBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DerivedTestBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.io.Serializable; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/DummyBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DummyBean.java similarity index 96% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/DummyBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DummyBean.java index cae1b3993305..cac5cced1c8a 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/DummyBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DummyBean.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * @author Costin Leau diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/DummyFactory.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DummyFactory.java similarity index 98% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/DummyFactory.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DummyFactory.java index 3939fc9372d6..2cf683a7c5fb 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/DummyFactory.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/DummyFactory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; diff --git a/spring-context/src/test/java/org/springframework/tests/sample/beans/Employee.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Employee.java similarity index 88% rename from spring-context/src/test/java/org/springframework/tests/sample/beans/Employee.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Employee.java index 86c3eedb19d8..3e9da7609e35 100644 --- a/spring-context/src/test/java/org/springframework/tests/sample/beans/Employee.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Employee.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; public class Employee extends TestBean { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethods.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/FactoryMethods.java similarity index 92% rename from spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethods.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/FactoryMethods.java index 49fb74a1dd4f..98b26798a2c8 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethods.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/FactoryMethods.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,13 +14,11 @@ * limitations under the License. */ -package org.springframework.beans.factory.xml; +package org.springframework.beans.testfixture.beans; import java.util.Collections; import java.util.List; -import org.springframework.tests.sample.beans.TestBean; - /** * Test class for Spring's ability to create objects using static * factory methods, rather than constructors. @@ -47,7 +45,7 @@ public static FactoryMethods newInstance(TestBean tb) { return new FactoryMethods(tb, "default", 0); } - protected static FactoryMethods newInstance(TestBean tb, int num, String name) { + public static FactoryMethods newInstance(TestBean tb, int num, String name) { if (name == null) { throw new IllegalStateException("Should never be called with null value"); } diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/GenericBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericBean.java similarity index 99% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/GenericBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericBean.java index 26b536b78664..2ad5ece17f5e 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/GenericBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.util.ArrayList; import java.util.Collection; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/GenericIntegerBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericIntegerBean.java similarity index 93% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/GenericIntegerBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericIntegerBean.java index 398ca1e06cd8..69fd56d17472 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/GenericIntegerBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericIntegerBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/GenericSetOfIntegerBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericSetOfIntegerBean.java similarity index 93% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/GenericSetOfIntegerBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericSetOfIntegerBean.java index cbd0a043a6b9..c0439f9fb669 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/GenericSetOfIntegerBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/GenericSetOfIntegerBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.util.Set; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/HasMap.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/HasMap.java similarity index 97% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/HasMap.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/HasMap.java index 29359e4c5581..c874077bd1b2 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/HasMap.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/HasMap.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.util.IdentityHashMap; import java.util.List; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/INestedTestBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/INestedTestBean.java similarity index 92% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/INestedTestBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/INestedTestBean.java index adf4f46168fb..3107e6b5f21c 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/INestedTestBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/INestedTestBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; public interface INestedTestBean { diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/IOther.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/IOther.java similarity index 92% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/IOther.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/IOther.java index f674ff7bb712..05059bcf6873 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/IOther.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/IOther.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; public interface IOther { diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/ITestBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/ITestBean.java similarity index 92% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/ITestBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/ITestBean.java index 1fe055dac0b6..742b39c4ea7e 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/ITestBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/ITestBean.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.io.IOException; /** - * Interface used for {@link org.springframework.tests.sample.beans.TestBean}. + * Interface used for {@link org.springframework.beans.testfixture.beans.TestBean}. * *

Two methods are the same as on Person, but if this * extends person it breaks quite a few tests.. diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/IndexedTestBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/IndexedTestBean.java similarity index 98% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/IndexedTestBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/IndexedTestBean.java index 2c8f85189fc7..02948f7eb854 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/IndexedTestBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/IndexedTestBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.util.ArrayList; import java.util.Collection; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/LifecycleBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/LifecycleBean.java similarity index 98% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/LifecycleBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/LifecycleBean.java index 67712dd76079..b2e54028270d 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/LifecycleBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/LifecycleBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/MustBeInitialized.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/MustBeInitialized.java similarity index 96% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/MustBeInitialized.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/MustBeInitialized.java index 2dde17d219f4..2e53ce2f885a 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/MustBeInitialized.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/MustBeInitialized.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import org.springframework.beans.factory.InitializingBean; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/NestedTestBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/NestedTestBean.java similarity index 96% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/NestedTestBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/NestedTestBean.java index 46e6a9110f67..ea26ec0072c0 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/NestedTestBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/NestedTestBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * Simple nested test bean used for testing bean factories, AOP framework etc. diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/NumberTestBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/NumberTestBean.java similarity index 97% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/NumberTestBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/NumberTestBean.java index 08b1649d42ad..224965b5c7a6 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/NumberTestBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/NumberTestBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.math.BigDecimal; import java.math.BigInteger; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/PackageLevelVisibleBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/PackageLevelVisibleBean.java similarity index 94% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/PackageLevelVisibleBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/PackageLevelVisibleBean.java index 1f446321132f..73a0bd3b9358 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/PackageLevelVisibleBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/PackageLevelVisibleBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * @see org.springframework.beans.factory.config.FieldRetrievingFactoryBeanTests diff --git a/spring-aop/src/test/java/org/springframework/tests/sample/beans/Person.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Person.java similarity index 94% rename from spring-aop/src/test/java/org/springframework/tests/sample/beans/Person.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Person.java index 1e9acb09646e..d57a8ca4267f 100644 --- a/spring-aop/src/test/java/org/springframework/tests/sample/beans/Person.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Person.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/Pet.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Pet.java similarity index 95% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/Pet.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Pet.java index 5e9040db0c0b..661eff92feb7 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/Pet.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/Pet.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * @author Rob Harrop diff --git a/spring-aop/src/test/java/org/springframework/tests/sample/beans/SerializablePerson.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/SerializablePerson.java similarity index 96% rename from spring-aop/src/test/java/org/springframework/tests/sample/beans/SerializablePerson.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/SerializablePerson.java index 0496d09a9682..6f9436906cc1 100644 --- a/spring-aop/src/test/java/org/springframework/tests/sample/beans/SerializablePerson.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/SerializablePerson.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.io.Serializable; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/SideEffectBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/SideEffectBean.java similarity index 94% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/SideEffectBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/SideEffectBean.java index ac09e8d76425..36911bdedcf1 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/SideEffectBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/SideEffectBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; /** * Bean that changes state on a business invocation, so that diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/TestAnnotation.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/TestAnnotation.java similarity index 93% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/TestAnnotation.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/TestAnnotation.java index ed1b8d528975..379c87419b5f 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/TestAnnotation.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/TestAnnotation.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/TestBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/TestBean.java similarity index 95% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/TestBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/TestBean.java index 1e83a21a13ce..ca3850a220a6 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/TestBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/TestBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; import java.io.IOException; import java.util.ArrayList; @@ -75,7 +75,7 @@ public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOt private Date date = new Date(); - private Float myFloat = new Float(0.0); + private Float myFloat = Float.valueOf(0.0f); private Collection friends = new LinkedList<>(); @@ -421,7 +421,7 @@ public void setPets(List pets) { /** - * @see org.springframework.tests.sample.beans.ITestBean#exceptional(Throwable) + * @see org.springframework.beans.testfixture.beans.ITestBean#exceptional(Throwable) */ @Override public void exceptional(Throwable t) throws Throwable { @@ -435,7 +435,7 @@ public void unreliableFileOperation() throws IOException { throw new IOException(); } /** - * @see org.springframework.tests.sample.beans.ITestBean#returnsThis() + * @see org.springframework.beans.testfixture.beans.ITestBean#returnsThis() */ @Override public Object returnsThis() { @@ -443,7 +443,7 @@ public Object returnsThis() { } /** - * @see org.springframework.tests.sample.beans.IOther#absquatulate() + * @see org.springframework.beans.testfixture.beans.IOther#absquatulate() */ @Override public void absquatulate() { diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/factory/DummyFactory.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/DummyFactory.java similarity index 97% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/factory/DummyFactory.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/DummyFactory.java index e707f05853d7..9e3d8b6511a2 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/factory/DummyFactory.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/DummyFactory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans.factory; +package org.springframework.beans.testfixture.beans.factory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; @@ -24,7 +24,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; /** * Simple factory to allow testing of FactoryBean support in AbstractBeanFactory. diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/package-info.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/package-info.java similarity index 56% rename from spring-beans/src/test/java/org/springframework/tests/sample/beans/package-info.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/package-info.java index 575bd1933f9b..14a1870d42b7 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/package-info.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/package-info.java @@ -1,4 +1,4 @@ /** * General purpose sample beans that can be used with tests. */ -package org.springframework.tests.sample.beans; +package org.springframework.beans.testfixture.beans; diff --git a/spring-aop/src/test/java/org/springframework/tests/sample/beans/subpkg/DeepBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/subpkg/DeepBean.java similarity index 74% rename from spring-aop/src/test/java/org/springframework/tests/sample/beans/subpkg/DeepBean.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/subpkg/DeepBean.java index 41dd7e33b9cb..50fc891ad832 100644 --- a/spring-aop/src/test/java/org/springframework/tests/sample/beans/subpkg/DeepBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/subpkg/DeepBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,12 @@ * limitations under the License. */ -package org.springframework.tests.sample.beans.subpkg; - -import org.springframework.aop.aspectj.AspectJExpressionPointcutTests; +package org.springframework.beans.testfixture.beans.subpkg; /** * Used for testing pointcut matching. * - * @see AspectJExpressionPointcutTests#testWithinRootAndSubpackages() + * @see org.springframework.aop.aspectj.AspectJExpressionPointcutTests#testWithinRootAndSubpackages() * * @author Chris Beams */ diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/AbstractBeanFactoryTests.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/factory/xml/AbstractBeanFactoryTests.java similarity index 97% rename from spring-beans/src/test/java/org/springframework/beans/factory/xml/AbstractBeanFactoryTests.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/factory/xml/AbstractBeanFactoryTests.java index 31c1984c35c3..307a9d64c12d 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/AbstractBeanFactoryTests.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/factory/xml/AbstractBeanFactoryTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.beans.factory.xml; +package org.springframework.beans.testfixture.factory.xml; import java.beans.PropertyEditorSupport; import java.util.StringTokenizer; @@ -29,10 +29,10 @@ import org.springframework.beans.factory.BeanNotOfRequiredTypeException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.tests.sample.beans.LifecycleBean; -import org.springframework.tests.sample.beans.MustBeInitialized; -import org.springframework.tests.sample.beans.TestBean; -import org.springframework.tests.sample.beans.factory.DummyFactory; +import org.springframework.beans.testfixture.beans.LifecycleBean; +import org.springframework.beans.testfixture.beans.MustBeInitialized; +import org.springframework.beans.testfixture.beans.TestBean; +import org.springframework.beans.testfixture.beans.factory.DummyFactory; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/AbstractListableBeanFactoryTests.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/factory/xml/AbstractListableBeanFactoryTests.java similarity index 91% rename from spring-beans/src/test/java/org/springframework/beans/factory/xml/AbstractListableBeanFactoryTests.java rename to spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/factory/xml/AbstractListableBeanFactoryTests.java index dbae0ebed703..0717f8a49366 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/AbstractListableBeanFactoryTests.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/factory/xml/AbstractListableBeanFactoryTests.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.springframework.beans.factory.xml; +package org.springframework.beans.testfixture.factory.xml; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.tests.sample.beans.TestBean; +import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; @@ -55,13 +55,13 @@ protected final void assertCount(int count) { protected void assertTestBeanCount(int count) { String[] defNames = getListableBeanFactory().getBeanNamesForType(TestBean.class, true, false); - assertThat(defNames.length == count).as("We should have " + count + " beans for class org.springframework.tests.sample.beans.TestBean, not " + + assertThat(defNames.length == count).as("We should have " + count + " beans for class org.springframework.beans.testfixture.beans.TestBean, not " + defNames.length).isTrue(); int countIncludingFactoryBeans = count + 2; String[] names = getListableBeanFactory().getBeanNamesForType(TestBean.class, true, true); assertThat(names.length == countIncludingFactoryBeans).as("We should have " + countIncludingFactoryBeans + - " beans for class org.springframework.tests.sample.beans.TestBean, not " + names.length).isTrue(); + " beans for class org.springframework.beans.testfixture.beans.TestBean, not " + names.length).isTrue(); } @Test diff --git a/spring-context-indexer/src/main/java/org/springframework/context/index/processor/SortedProperties.java b/spring-context-indexer/src/main/java/org/springframework/context/index/processor/SortedProperties.java index 0281cf4b68da..127a1a2b9614 100644 --- a/spring-context-indexer/src/main/java/org/springframework/context/index/processor/SortedProperties.java +++ b/spring-context-indexer/src/main/java/org/springframework/context/index/processor/SortedProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -88,7 +88,7 @@ class SortedProperties extends Properties { public void store(OutputStream out, String comments) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); super.store(baos, (this.omitComments ? null : comments)); - String contents = new String(baos.toByteArray(), StandardCharsets.ISO_8859_1); + String contents = baos.toString(StandardCharsets.ISO_8859_1.name()); for (String line : contents.split(EOL)) { if (!(this.omitComments && line.startsWith("#"))) { out.write((line + EOL).getBytes(StandardCharsets.ISO_8859_1)); diff --git a/spring-context-indexer/src/test/java/org/springframework/context/index/sample/SampleNone.java b/spring-context-indexer/src/test/java/org/springframework/context/index/sample/SampleNone.java index bd1cd72401f2..f81de9365b85 100644 --- a/spring-context-indexer/src/test/java/org/springframework/context/index/sample/SampleNone.java +++ b/spring-context-indexer/src/test/java/org/springframework/context/index/sample/SampleNone.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package org.springframework.context.index.sample; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.core.type.Scope; /** * Candidate with no matching annotation. diff --git a/spring-context/src/test/java/org/springframework/context/TestListener.java b/spring-context-indexer/src/test/java/org/springframework/context/index/sample/Scope.java similarity index 54% rename from spring-context/src/test/java/org/springframework/context/TestListener.java rename to spring-context-indexer/src/test/java/org/springframework/context/index/sample/Scope.java index bc8949f2700d..b96de6139374 100644 --- a/spring-context/src/test/java/org/springframework/context/TestListener.java +++ b/spring-context-indexer/src/test/java/org/springframework/context/index/sample/Scope.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,29 +14,20 @@ * limitations under the License. */ -package org.springframework.context; +package org.springframework.context.index.sample; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; /** - * Listener that maintains a global count of events. - * - * @author Rod Johnson - * @since January 21, 2001 + * Copy of the {@code @Scope} annotation for testing purposes. */ -public class TestListener implements ApplicationListener { - - private int eventCount; - - public int getEventCount() { - return eventCount; - } - - public void zeroCounter() { - eventCount = 0; - } +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Scope { - @Override - public void onApplicationEvent(ApplicationEvent e) { - ++eventCount; - } + String value() default "singleton"; } diff --git a/spring-context-support/spring-context-support.gradle b/spring-context-support/spring-context-support.gradle index 54bf50e43335..f8a8631293ad 100644 --- a/spring-context-support/spring-context-support.gradle +++ b/spring-context-support/spring-context-support.gradle @@ -15,6 +15,10 @@ dependencies { optional("org.codehaus.fabric3.api:commonj") optional("org.freemarker:freemarker") testCompile(project(":spring-context")) + testCompile(testFixtures(project(":spring-beans"))) + testCompile(testFixtures(project(":spring-context"))) + testCompile(testFixtures(project(":spring-core"))) + testCompile(testFixtures(project(":spring-tx"))) testCompile("org.hsqldb:hsqldb") testCompile("org.hibernate:hibernate-validator") testCompile("javax.annotation:javax.annotation-api") @@ -22,4 +26,7 @@ dependencies { testRuntime("org.ehcache:ehcache") testRuntime("org.glassfish:javax.el") testRuntime("com.sun.mail:javax.mail") + testFixturesApi("org.junit.jupiter:junit-jupiter-api") + testFixturesImplementation("org.assertj:assertj-core") + testFixturesImplementation("org.mockito:mockito-core") } diff --git a/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCache.java b/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCache.java index 34dc622f8b2b..a19884b19ce8 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCache.java +++ b/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ * @author Juergen Hoeller * @author Stephane Nicoll * @since 4.3 + * @see CaffeineCacheManager */ public class CaffeineCache extends AbstractValueAdaptingCache { diff --git a/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java b/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java index 54331f8909d0..d5b77cbc1bb9 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java +++ b/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.Caffeine; @@ -50,15 +50,12 @@ * @author Ben Manes * @author Juergen Hoeller * @author Stephane Nicoll + * @author Sam Brannen * @since 4.3 * @see CaffeineCache */ public class CaffeineCacheManager implements CacheManager { - private final ConcurrentMap cacheMap = new ConcurrentHashMap<>(16); - - private boolean dynamic = true; - private Caffeine cacheBuilder = Caffeine.newBuilder(); @Nullable @@ -66,6 +63,12 @@ public class CaffeineCacheManager implements CacheManager { private boolean allowNullValues = true; + private boolean dynamic = true; + + private final Map cacheMap = new ConcurrentHashMap<>(16); + + private final Collection customCacheNames = new CopyOnWriteArrayList<>(); + /** * Construct a dynamic CaffeineCacheManager, @@ -134,6 +137,13 @@ public void setCacheSpecification(String cacheSpecification) { doSetCaffeine(Caffeine.from(cacheSpecification)); } + private void doSetCaffeine(Caffeine cacheBuilder) { + if (!ObjectUtils.nullSafeEquals(this.cacheBuilder, cacheBuilder)) { + this.cacheBuilder = cacheBuilder; + refreshCommonCaches(); + } + } + /** * Set the Caffeine CacheLoader to use for building each individual * {@link CaffeineCache} instance, turning it into a LoadingCache. @@ -144,7 +154,7 @@ public void setCacheSpecification(String cacheSpecification) { public void setCacheLoader(CacheLoader cacheLoader) { if (!ObjectUtils.nullSafeEquals(this.cacheLoader, cacheLoader)) { this.cacheLoader = cacheLoader; - refreshKnownCaches(); + refreshCommonCaches(); } } @@ -157,7 +167,7 @@ public void setCacheLoader(CacheLoader cacheLoader) { public void setAllowNullValues(boolean allowNullValues) { if (this.allowNullValues != allowNullValues) { this.allowNullValues = allowNullValues; - refreshKnownCaches(); + refreshCommonCaches(); } } @@ -178,55 +188,80 @@ public Collection getCacheNames() { @Override @Nullable public Cache getCache(String name) { - Cache cache = this.cacheMap.get(name); - if (cache == null && this.dynamic) { - synchronized (this.cacheMap) { - cache = this.cacheMap.get(name); - if (cache == null) { - cache = createCaffeineCache(name); - this.cacheMap.put(name, cache); - } - } - } - return cache; + return this.cacheMap.computeIfAbsent(name, cacheName -> + this.dynamic ? createCaffeineCache(cacheName) : null); } + /** - * Create a new CaffeineCache instance for the specified cache name. + * Register the given native Caffeine Cache instance with this cache manager, + * adapting it to Spring's cache API for exposure through {@link #getCache}. + * Any number of such custom caches may be registered side by side. + *

This allows for custom settings per cache (as opposed to all caches + * sharing the common settings in the cache manager's configuration) and + * is typically used with the Caffeine builder API: + * {@code registerCustomCache("myCache", Caffeine.newBuilder().maximumSize(10).build())} + *

Note that any other caches, whether statically specified through + * {@link #setCacheNames} or dynamically built on demand, still operate + * with the common settings in the cache manager's configuration. + * @param name the name of the cache + * @param cache the custom Caffeine Cache instance to register + * @since 5.2.8 + * @see #adaptCaffeineCache + */ + public void registerCustomCache(String name, com.github.benmanes.caffeine.cache.Cache cache) { + this.customCacheNames.add(name); + this.cacheMap.put(name, adaptCaffeineCache(name, cache)); + } + + /** + * Adapt the given new native Caffeine Cache instance to Spring's {@link Cache} + * abstraction for the specified cache name. * @param name the name of the cache + * @param cache the native Caffeine Cache instance * @return the Spring CaffeineCache adapter (or a decorator thereof) + * @since 5.2.8 + * @see CaffeineCache + * @see #isAllowNullValues() + */ + protected Cache adaptCaffeineCache(String name, com.github.benmanes.caffeine.cache.Cache cache) { + return new CaffeineCache(name, cache, isAllowNullValues()); + } + + /** + * Build a common {@link CaffeineCache} instance for the specified cache name, + * using the common Caffeine configuration specified on this cache manager. + *

Delegates to {@link #adaptCaffeineCache} as the adaptation method to + * Spring's cache abstraction (allowing for centralized decoration etc), + * passing in a freshly built native Caffeine Cache instance. + * @param name the name of the cache + * @return the Spring CaffeineCache adapter (or a decorator thereof) + * @see #adaptCaffeineCache + * @see #createNativeCaffeineCache */ protected Cache createCaffeineCache(String name) { - return new CaffeineCache(name, createNativeCaffeineCache(name), isAllowNullValues()); + return adaptCaffeineCache(name, createNativeCaffeineCache(name)); } /** - * Create a native Caffeine Cache instance for the specified cache name. + * Build a common Caffeine Cache instance for the specified cache name, + * using the common Caffeine configuration specified on this cache manager. * @param name the name of the cache * @return the native Caffeine Cache instance + * @see #createCaffeineCache */ protected com.github.benmanes.caffeine.cache.Cache createNativeCaffeineCache(String name) { - if (this.cacheLoader != null) { - return this.cacheBuilder.build(this.cacheLoader); - } - else { - return this.cacheBuilder.build(); - } - } - - private void doSetCaffeine(Caffeine cacheBuilder) { - if (!ObjectUtils.nullSafeEquals(this.cacheBuilder, cacheBuilder)) { - this.cacheBuilder = cacheBuilder; - refreshKnownCaches(); - } + return (this.cacheLoader != null ? this.cacheBuilder.build(this.cacheLoader) : this.cacheBuilder.build()); } /** - * Create the known caches again with the current state of this manager. + * Recreate the common caches with the current state of this manager. */ - private void refreshKnownCaches() { + private void refreshCommonCaches() { for (Map.Entry entry : this.cacheMap.entrySet()) { - entry.setValue(createCaffeineCache(entry.getKey())); + if (!this.customCacheNames.contains(entry.getKey())) { + entry.setValue(createCaffeineCache(entry.getKey())); + } } } diff --git a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCache.java b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCache.java index 26ea8929d3a6..4309fa73a2cb 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCache.java +++ b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ * @author Juergen Hoeller * @author Stephane Nicoll * @since 3.1 + * @see EhCacheCacheManager */ public class EhCacheCache implements Cache { diff --git a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java index 709404e6f2dc..f3e58a55b288 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java +++ b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ * @author Juergen Hoeller * @author Stephane Nicoll * @since 3.1 + * @see EhCacheCache */ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManager { diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCache.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCache.java index 73c6176a5e99..84d2e3f9bcf2 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCache.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ * @author Juergen Hoeller * @author Stephane Nicoll * @since 3.2 + * @see JCacheCacheManager */ public class JCacheCache extends AbstractValueAdaptingCache { diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java index 08c2b0ec27c1..e4feb09554ba 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ * @author Juergen Hoeller * @author Stephane Nicoll * @since 3.2 + * @see JCacheCache */ public class JCacheCacheManager extends AbstractTransactionSupportingCacheManager { diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java index 8f751a990082..34bb1a08d63e 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,7 @@ * @see JCacheConfigurer */ @Configuration -public class AbstractJCacheConfiguration extends AbstractCachingConfiguration { +public abstract class AbstractJCacheConfiguration extends AbstractCachingConfiguration { @Nullable protected Supplier exceptionCacheResolver; diff --git a/spring-context-support/src/main/java/org/springframework/mail/SimpleMailMessage.java b/spring-context-support/src/main/java/org/springframework/mail/SimpleMailMessage.java index 303836769542..95268a2993e0 100644 --- a/spring-context-support/src/main/java/org/springframework/mail/SimpleMailMessage.java +++ b/spring-context-support/src/main/java/org/springframework/mail/SimpleMailMessage.java @@ -276,9 +276,7 @@ private static String[] copyOrNull(@Nullable String[] state) { } private static String[] copy(String[] state) { - String[] copy = new String[state.length]; - System.arraycopy(state, 0, copy, 0, state.length); - return copy; + return state.clone(); } } diff --git a/spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java b/spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java index b5e37e3698ab..c9d21201a67f 100644 --- a/spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java +++ b/spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -159,8 +159,6 @@ public class MimeMessageHelper { private static final String HEADER_PRIORITY = "X-Priority"; - private static final String HEADER_CONTENT_ID = "Content-ID"; - private final MimeMessage mimeMessage; @@ -175,6 +173,8 @@ public class MimeMessageHelper { private FileTypeMap fileTypeMap; + private boolean encodeFilenames = true; + private boolean validateAddresses = false; @@ -464,7 +464,7 @@ protected FileTypeMap getDefaultFileTypeMap(MimeMessage mimeMessage) { * Set the Java Activation Framework {@code FileTypeMap} to use * for determining the content type of inline content and attachments * that get added to the message. - *

Default is the {@code FileTypeMap} that the underlying + *

The default is the {@code FileTypeMap} that the underlying * MimeMessage carries, if any, or the Activation Framework's default * {@code FileTypeMap} instance else. * @see #addInline @@ -480,18 +480,40 @@ public void setFileTypeMap(@Nullable FileTypeMap fileTypeMap) { /** * Return the {@code FileTypeMap} used by this MimeMessageHelper. + * @see #setFileTypeMap */ public FileTypeMap getFileTypeMap() { return this.fileTypeMap; } + /** + * Set whether to encode attachment filenames passed to this helper's + * {@code #addAttachment} methods. + *

The default is {@code true} for compatibility with older email clients; + * turn this to {@code false} for standard MIME behavior. On a related note, + * check out JavaMail's {@code mail.mime.encodefilename} system property. + * @since 5.2.9 + * @see #addAttachment(String, DataSource) + * @see MimeBodyPart#setFileName(String) + */ + public void setEncodeFilenames(boolean encodeFilenames) { + this.encodeFilenames = encodeFilenames; + } + + /** + * Return whether to encode attachment filenames passed to this helper's + * {@code #addAttachment} methods. + * @since 5.2.9 + * @see #setEncodeFilenames + */ + public boolean isEncodeFilenames() { + return this.encodeFilenames; + } + /** * Set whether to validate all addresses which get passed to this helper. - * Default is "false". - *

Note that this is by default just available for JavaMail >= 1.3. - * You can override the default {@code validateAddress method} for - * validation on older JavaMail versions (or for custom validation). + *

The default is {@code false}. * @see #validateAddress */ public void setValidateAddresses(boolean validateAddresses) { @@ -500,6 +522,7 @@ public void setValidateAddresses(boolean validateAddresses) { /** * Return whether this helper will validate all addresses passed to it. + * @see #setValidateAddresses */ public boolean isValidateAddresses() { return this.validateAddresses; @@ -508,10 +531,8 @@ public boolean isValidateAddresses() { /** * Validate the given mail address. * Called by all of MimeMessageHelper's address setters and adders. - *

Default implementation invokes {@code InternetAddress.validate()}, + *

The default implementation invokes {@link InternetAddress#validate()}, * provided that address validation is activated for the helper instance. - *

Note that this method will just work on JavaMail >= 1.3. You can override - * it for validation on older JavaMail versions or for custom validation. * @param address the address to validate * @throws AddressException if validation failed * @see #isValidateAddresses() @@ -525,7 +546,8 @@ protected void validateAddress(InternetAddress address) throws AddressException /** * Validate all given mail addresses. - * Default implementation simply delegates to validateAddress for each address. + *

The default implementation simply delegates to {@link #validateAddress} + * for each address. * @param addresses the addresses to validate * @throws AddressException if validation failed * @see #validateAddress(InternetAddress) @@ -885,9 +907,7 @@ public void addInline(String contentId, DataSource dataSource) throws MessagingE Assert.notNull(dataSource, "DataSource must not be null"); MimeBodyPart mimeBodyPart = new MimeBodyPart(); mimeBodyPart.setDisposition(MimeBodyPart.INLINE); - // We're using setHeader here to remain compatible with JavaMail 1.2, - // rather than JavaMail 1.3's setContentID. - mimeBodyPart.setHeader(HEADER_CONTENT_ID, "<" + contentId + ">"); + mimeBodyPart.setContentID("<" + contentId + ">"); mimeBodyPart.setDataHandler(new DataHandler(dataSource)); getMimeMultipart().addBodyPart(mimeBodyPart); } @@ -997,7 +1017,8 @@ public void addAttachment(String attachmentFilename, DataSource dataSource) thro try { MimeBodyPart mimeBodyPart = new MimeBodyPart(); mimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT); - mimeBodyPart.setFileName(MimeUtility.encodeText(attachmentFilename)); + mimeBodyPart.setFileName(isEncodeFilenames() ? + MimeUtility.encodeText(attachmentFilename) : attachmentFilename); mimeBodyPart.setDataHandler(new DataHandler(dataSource)); getRootMimeMultipart().addBodyPart(mimeBodyPart); } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java index f20fde56b175..a9adcc823d5a 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,13 +58,13 @@ *

The CommonJ WorkManager will usually be retrieved from the application * server's JNDI environment, as defined in the server's management console. * - *

Note: On the upcoming EE 7 compliant versions of WebLogic and WebSphere, a + *

Note: On EE 7/8 compliant versions of WebLogic and WebSphere, a * {@link org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor} - * should be preferred, following JSR-236 support in Java EE 7. + * should be preferred, following JSR-236 support in Java EE 7/8. * * @author Juergen Hoeller * @since 2.0 - * @deprecated as of 5.1, in favor of EE 7's + * @deprecated as of 5.1, in favor of the EE 7/8 based * {@link org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor} */ @Deprecated @@ -121,6 +121,11 @@ public void setWorkListener(WorkListener workListener) { * execution callback (which may be a wrapper around the user-supplied task). *

The primary use case is to set some execution context around the task's * invocation, or to provide some monitoring/statistics for task execution. + *

NOTE: Exception handling in {@code TaskDecorator} implementations + * is limited to plain {@code Runnable} execution via {@code execute} calls. + * In case of {@code #submit} calls, the exposed {@code Runnable} will be a + * {@code FutureTask} which does not propagate any exceptions; you might + * have to cast it and call {@code Future#get} to evaluate exceptions. * @since 4.3 */ public void setTaskDecorator(TaskDecorator taskDecorator) { diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java index d5e0af1779b4..4543f95b0d01 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.scheduling.quartz; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.SQLException; import javax.sql.DataSource; @@ -57,6 +58,8 @@ * @since 1.1 * @see SchedulerFactoryBean#setDataSource * @see SchedulerFactoryBean#setNonTransactionalDataSource + * @see SchedulerFactoryBean#getConfigTimeDataSource() + * @see SchedulerFactoryBean#getConfigTimeNonTransactionalDataSource() * @see org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection */ @@ -110,7 +113,6 @@ public Connection getConnection() throws SQLException { public void shutdown() { // Do nothing - a Spring-managed DataSource has its own lifecycle. } - /* Quartz 2.2 initialize method */ @Override public void initialize() { // Do nothing - a Spring-managed DataSource has its own lifecycle. @@ -139,7 +141,6 @@ public Connection getConnection() throws SQLException { public void shutdown() { // Do nothing - a Spring-managed DataSource has its own lifecycle. } - /* Quartz 2.2 initialize method */ @Override public void initialize() { // Do nothing - a Spring-managed DataSource has its own lifecycle. @@ -149,7 +150,8 @@ public void initialize() { // No, if HSQL is the platform, we really don't want to use locks... try { - String productName = JdbcUtils.extractDatabaseMetaData(this.dataSource, "getDatabaseProductName"); + String productName = JdbcUtils.extractDatabaseMetaData(this.dataSource, + DatabaseMetaData::getDatabaseProductName); productName = JdbcUtils.commonDatabaseName(productName); if (productName != null && productName.toLowerCase().contains("hsql")) { setUseDBLocks(false); diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/ResourceLoaderClassLoadHelper.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/ResourceLoaderClassLoadHelper.java index 1b274b79f316..996a598460d2 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/ResourceLoaderClassLoadHelper.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/ResourceLoaderClassLoadHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,8 +81,8 @@ public Class loadClass(String name) throws ClassNotFoundException { return ClassUtils.forName(name, this.resourceLoader.getClassLoader()); } - @Override @SuppressWarnings("unchecked") + @Override public Class loadClass(String name, Class clazz) throws ClassNotFoundException { return (Class) loadClass(name); } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java index 50ef456cfc9a..9136111d9e90 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -313,6 +313,7 @@ public void setTaskExecutor(Executor taskExecutor) { * If set, this will override corresponding settings in Quartz properties. *

Note: If this is set, the Quartz settings should not define * a job store "dataSource" to avoid meaningless double configuration. + * Also, do not define a "org.quartz.jobStore.class" property at all. *

A Spring-specific subclass of Quartz' JobStoreCMT will be used. * It is therefore strongly recommended to perform all operations on * the Scheduler within Spring-managed (or plain JTA) transactions. diff --git a/spring-context-support/src/main/java/org/springframework/ui/freemarker/FreeMarkerTemplateUtils.java b/spring-context-support/src/main/java/org/springframework/ui/freemarker/FreeMarkerTemplateUtils.java index 2c9fa7e4781b..e1ca06bf99e3 100644 --- a/spring-context-support/src/main/java/org/springframework/ui/freemarker/FreeMarkerTemplateUtils.java +++ b/spring-context-support/src/main/java/org/springframework/ui/freemarker/FreeMarkerTemplateUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ public abstract class FreeMarkerTemplateUtils { public static String processTemplateIntoString(Template template, Object model) throws IOException, TemplateException { - StringWriter result = new StringWriter(); + StringWriter result = new StringWriter(1024); template.process(model, result); return result.toString(); } diff --git a/spring-context-support/src/main/resources/.gitignore b/spring-context-support/src/main/resources/.gitignore deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheManagerTests.java b/spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheManagerTests.java index 7637e1054542..e90a3ece9363 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheManagerTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -125,7 +125,7 @@ public void changeCaffeineRecreateCache() { Cache cache1x = cm.getCache("c1"); assertThat(cache1x != cache1).isTrue(); - cm.setCaffeine(caffeine); // Set same instance + cm.setCaffeine(caffeine); // Set same instance Cache cache1xx = cm.getCache("c1"); assertThat(cache1xx).isSameAs(cache1x); } @@ -155,12 +155,14 @@ public void changeCacheLoaderRecreateCache() { CaffeineCacheManager cm = new CaffeineCacheManager("c1"); Cache cache1 = cm.getCache("c1"); - CacheLoader loader = mockCacheLoader(); + @SuppressWarnings("unchecked") + CacheLoader loader = mock(CacheLoader.class); + cm.setCacheLoader(loader); Cache cache1x = cm.getCache("c1"); assertThat(cache1x != cache1).isTrue(); - cm.setCacheLoader(loader); // Set same instance + cm.setCacheLoader(loader); // Set same instance Cache cache1xx = cm.getCache("c1"); assertThat(cache1xx).isSameAs(cache1x); } @@ -194,9 +196,19 @@ public Object load(Object key) throws Exception { .withMessageContaining("I only know ping"); } - @SuppressWarnings("unchecked") - private CacheLoader mockCacheLoader() { - return mock(CacheLoader.class); + @Test + public void customCacheRegistration() { + CaffeineCacheManager cm = new CaffeineCacheManager("c1"); + com.github.benmanes.caffeine.cache.Cache nc = Caffeine.newBuilder().build(); + cm.registerCustomCache("c2", nc); + + Cache cache1 = cm.getCache("c1"); + Cache cache2 = cm.getCache("c2"); + assertThat(nc == cache2.getNativeCache()).isTrue(); + + cm.setCaffeine(Caffeine.newBuilder().maximumSize(10)); + assertThat(cm.getCache("c1") != cache1).isTrue(); + assertThat(cm.getCache("c2") == cache2).isTrue(); } } diff --git a/spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheTests.java b/spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheTests.java index eae5f14bb449..48e1fd5a9393 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheTests.java @@ -20,8 +20,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.cache.AbstractValueAdaptingCacheTests; import org.springframework.cache.Cache; +import org.springframework.context.testfixture.cache.AbstractValueAdaptingCacheTests; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTests.java b/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTests.java index df0e02b72ae7..b9bb1cc8542a 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTests.java @@ -25,11 +25,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.cache.AbstractCacheTests; -import org.springframework.tests.EnabledForTestGroups; +import org.springframework.context.testfixture.cache.AbstractCacheTests; +import org.springframework.core.testfixture.EnabledForTestGroups; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.tests.TestGroup.LONG_RUNNING; +import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING; /** * @author Costin Leau diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheAnnotationTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheAnnotationTests.java index 1c0031854174..188cc293c974 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheAnnotationTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheAnnotationTests.java @@ -28,19 +28,19 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.config.AbstractCacheAnnotationTests; -import org.springframework.cache.config.AnnotatedClassCacheableService; -import org.springframework.cache.config.CacheableService; -import org.springframework.cache.config.DefaultCacheableService; -import org.springframework.cache.config.SomeCustomKeyGenerator; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.cache.interceptor.SimpleKeyGenerator; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.tests.transaction.CallCountingTransactionManager; +import org.springframework.context.testfixture.cache.AbstractCacheAnnotationTests; +import org.springframework.context.testfixture.cache.SomeCustomKeyGenerator; +import org.springframework.context.testfixture.cache.beans.AnnotatedClassCacheableService; +import org.springframework.context.testfixture.cache.beans.CacheableService; +import org.springframework.context.testfixture.cache.beans.DefaultCacheableService; import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.transaction.testfixture.CallCountingTransactionManager; /** * @author Stephane Nicoll diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheApiTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheApiTests.java index d0797dd92696..b826e2a3fb37 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheApiTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheApiTests.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.springframework.cache.AbstractValueAdaptingCacheTests; +import org.springframework.context.testfixture.cache.AbstractValueAdaptingCacheTests; /** * @author Stephane Nicoll diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheCustomInterceptorTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheCustomInterceptorTests.java index 8ac2f4a3e6b0..6d5714d09574 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheCustomInterceptorTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheCustomInterceptorTests.java @@ -37,6 +37,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.contextsupport.testfixture.jcache.JCacheableService; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheJavaConfigTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheJavaConfigTests.java index 60555a7a3e76..9288994fc6f0 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheJavaConfigTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheJavaConfigTests.java @@ -25,7 +25,6 @@ import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.concurrent.ConcurrentMapCache; import org.springframework.cache.concurrent.ConcurrentMapCacheManager; -import org.springframework.cache.config.SomeKeyGenerator; import org.springframework.cache.interceptor.CacheErrorHandler; import org.springframework.cache.interceptor.CacheResolver; import org.springframework.cache.interceptor.KeyGenerator; @@ -43,6 +42,9 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.testfixture.cache.SomeKeyGenerator; +import org.springframework.contextsupport.testfixture.jcache.AbstractJCacheAnnotationTests; +import org.springframework.contextsupport.testfixture.jcache.JCacheableService; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheNamespaceDrivenTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheNamespaceDrivenTests.java index 28f7c513c76d..262689f83ad8 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheNamespaceDrivenTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheNamespaceDrivenTests.java @@ -24,6 +24,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; +import org.springframework.contextsupport.testfixture.jcache.AbstractJCacheAnnotationTests; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheStandaloneConfigTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheStandaloneConfigTests.java index c57d7ecc2134..f07e5214850e 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheStandaloneConfigTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheStandaloneConfigTests.java @@ -18,6 +18,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; +import org.springframework.contextsupport.testfixture.jcache.AbstractJCacheAnnotationTests; /** * @author Stephane Nicoll diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotatedJCacheableService.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotatedJCacheableService.java index 1e44ab251d02..e5cfb12b64e6 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotatedJCacheableService.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotatedJCacheableService.java @@ -30,9 +30,9 @@ import org.springframework.cache.Cache; import org.springframework.cache.interceptor.SimpleKeyGenerator; -import org.springframework.cache.jcache.config.JCacheableService; -import org.springframework.cache.jcache.support.TestableCacheKeyGenerator; -import org.springframework.cache.jcache.support.TestableCacheResolverFactory; +import org.springframework.contextsupport.testfixture.cache.TestableCacheKeyGenerator; +import org.springframework.contextsupport.testfixture.cache.TestableCacheResolverFactory; +import org.springframework.contextsupport.testfixture.jcache.JCacheableService; /** * Repository sample with a @CacheDefaults annotation diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotationCacheOperationSourceTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotationCacheOperationSourceTests.java index 6a2e6d756b01..bcc9276243bd 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotationCacheOperationSourceTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotationCacheOperationSourceTests.java @@ -32,9 +32,9 @@ import org.springframework.cache.interceptor.CacheResolver; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.cache.jcache.AbstractJCacheTests; -import org.springframework.cache.jcache.support.TestableCacheKeyGenerator; -import org.springframework.cache.jcache.support.TestableCacheResolver; -import org.springframework.cache.jcache.support.TestableCacheResolverFactory; +import org.springframework.contextsupport.testfixture.cache.TestableCacheKeyGenerator; +import org.springframework.contextsupport.testfixture.cache.TestableCacheResolver; +import org.springframework.contextsupport.testfixture.cache.TestableCacheResolverFactory; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; diff --git a/spring-context-support/src/test/java/org/springframework/cache/transaction/TransactionAwareCacheDecoratorTests.java b/spring-context-support/src/test/java/org/springframework/cache/transaction/TransactionAwareCacheDecoratorTests.java index 74337eb76e48..66369edfe6c0 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/transaction/TransactionAwareCacheDecoratorTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/transaction/TransactionAwareCacheDecoratorTests.java @@ -20,8 +20,8 @@ import org.springframework.cache.Cache; import org.springframework.cache.concurrent.ConcurrentMapCache; -import org.springframework.tests.transaction.CallCountingTransactionManager; import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.transaction.testfixture.CallCountingTransactionManager; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; diff --git a/spring-context-support/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java b/spring-context-support/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java index b2503fb7db35..a30b1c291212 100644 --- a/spring-context-support/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java +++ b/spring-context-support/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java @@ -34,19 +34,19 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.StaticApplicationContext; import org.springframework.core.task.TaskExecutor; +import org.springframework.core.testfixture.EnabledForTestGroups; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.tests.EnabledForTestGroups; -import org.springframework.tests.sample.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.springframework.tests.TestGroup.PERFORMANCE; +import static org.springframework.core.testfixture.TestGroup.PERFORMANCE; /** * @author Juergen Hoeller diff --git a/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/BeanValidationPostProcessorTests.java b/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/BeanValidationPostProcessorTests.java index 0f6e099f6f48..4d014707077a 100644 --- a/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/BeanValidationPostProcessorTests.java +++ b/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/BeanValidationPostProcessorTests.java @@ -24,9 +24,9 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor; import org.springframework.context.support.GenericApplicationContext; -import org.springframework.tests.sample.beans.TestBean; import org.springframework.validation.beanvalidation.BeanValidationPostProcessor; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/SpringValidatorAdapterTests.java b/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/SpringValidatorAdapterTests.java index 7639b6704b48..99f9d412910d 100644 --- a/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/SpringValidatorAdapterTests.java +++ b/spring-context-support/src/test/java/org/springframework/validation/beanvalidation2/SpringValidatorAdapterTests.java @@ -52,8 +52,8 @@ import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; import org.springframework.context.support.StaticMessageSource; +import org.springframework.core.testfixture.io.SerializationTestUtils; import org.springframework.util.ObjectUtils; -import org.springframework.util.SerializationTestUtils; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.beanvalidation.SpringValidatorAdapter; diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/support/TestableCacheKeyGenerator.java b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/cache/TestableCacheKeyGenerator.java similarity index 96% rename from spring-context-support/src/test/java/org/springframework/cache/jcache/support/TestableCacheKeyGenerator.java rename to spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/cache/TestableCacheKeyGenerator.java index 3e881dd519e0..9bb225ba80f9 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/support/TestableCacheKeyGenerator.java +++ b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/cache/TestableCacheKeyGenerator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cache.jcache.support; +package org.springframework.contextsupport.testfixture.cache; import java.lang.annotation.Annotation; diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/support/TestableCacheResolver.java b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/cache/TestableCacheResolver.java similarity index 95% rename from spring-context-support/src/test/java/org/springframework/cache/jcache/support/TestableCacheResolver.java rename to spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/cache/TestableCacheResolver.java index 519ba73422de..04567b1a8459 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/support/TestableCacheResolver.java +++ b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/cache/TestableCacheResolver.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cache.jcache.support; +package org.springframework.contextsupport.testfixture.cache; import java.lang.annotation.Annotation; diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/support/TestableCacheResolverFactory.java b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/cache/TestableCacheResolverFactory.java similarity index 95% rename from spring-context-support/src/test/java/org/springframework/cache/jcache/support/TestableCacheResolverFactory.java rename to spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/cache/TestableCacheResolverFactory.java index c544dde8bbe9..5849090acd1b 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/support/TestableCacheResolverFactory.java +++ b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/cache/TestableCacheResolverFactory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cache.jcache.support; +package org.springframework.contextsupport.testfixture.cache; import java.lang.annotation.Annotation; diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/AbstractJCacheAnnotationTests.java b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/jcache/AbstractJCacheAnnotationTests.java similarity index 99% rename from spring-context-support/src/test/java/org/springframework/cache/jcache/config/AbstractJCacheAnnotationTests.java rename to spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/jcache/AbstractJCacheAnnotationTests.java index aa6478acec69..db5bb038e94f 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/AbstractJCacheAnnotationTests.java +++ b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/jcache/AbstractJCacheAnnotationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cache.jcache.config; +package org.springframework.contextsupport.testfixture.jcache; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheableService.java b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/jcache/JCacheableService.java similarity index 96% rename from spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheableService.java rename to spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/jcache/JCacheableService.java index 1c43cfbea2e5..db36d1103207 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheableService.java +++ b/spring-context-support/src/testFixtures/java/org/springframework/contextsupport/testfixture/jcache/JCacheableService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cache.jcache.config; +package org.springframework.contextsupport.testfixture.jcache; import java.io.IOException; diff --git a/spring-context/spring-context.gradle b/spring-context/spring-context.gradle index 54ee48da69ac..30ab5d6e9a6a 100644 --- a/spring-context/spring-context.gradle +++ b/spring-context/spring-context.gradle @@ -15,29 +15,35 @@ dependencies { optional("javax.inject:javax.inject") optional("javax.interceptor:javax.interceptor-api") optional("javax.money:money-api") - // TODO: overriding 2.0.1.Final, because of LocalValidatorFactoryBean + // Overriding 2.0.1.Final due to Bean Validation 1.1 compatibility in LocalValidatorFactoryBean optional("javax.validation:validation-api:1.1.0.Final") optional("javax.xml.ws:jaxws-api") optional("org.aspectj:aspectjweaver") optional("org.codehaus.groovy:groovy") - optional("org.beanshell:bsh") + optional("org.apache-extras.beanshell:bsh") optional("joda-time:joda-time") optional("org.hibernate:hibernate-validator:5.4.3.Final") optional("org.jetbrains.kotlin:kotlin-reflect") optional("org.jetbrains.kotlin:kotlin-stdlib") optional("org.reactivestreams:reactive-streams") + testCompile(testFixtures(project(":spring-aop"))) + testCompile(testFixtures(project(":spring-beans"))) + testCompile(testFixtures(project(":spring-core"))) testCompile("io.projectreactor:reactor-core") testCompile("org.codehaus.groovy:groovy-jsr223") testCompile("org.codehaus.groovy:groovy-test") testCompile("org.codehaus.groovy:groovy-xml") testCompile("org.apache.commons:commons-pool2") - testCompile("javax.inject:javax.inject-tck") - // Substitute for "javax.management:jmxremote_optional:1.0.1_04" which - // is not available on Maven Central - testRuntime("org.glassfish.external:opendmk_jmxremote_optional_jar") testCompile("org.awaitility:awaitility") + testCompile("javax.inject:javax.inject-tck") testRuntime("javax.xml.bind:jaxb-api") testRuntime("org.glassfish:javax.el") + // Substitute for javax.management:jmxremote_optional:1.0.1_04 (not available on Maven Central) + testRuntime("org.glassfish.external:opendmk_jmxremote_optional_jar") testRuntime("org.javamoney:moneta") testRuntime("org.junit.vintage:junit-vintage-engine") // for @Inject TCK + testFixturesApi("org.junit.jupiter:junit-jupiter-api") + testFixturesImplementation(testFixtures(project(":spring-beans"))) + testFixturesImplementation("com.google.code.findbugs:jsr305") + testFixturesImplementation("org.assertj:assertj-core") } diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java b/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java index 8743df7e668b..abf47bfd0fa1 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,8 @@ * *

In contrast to the {@link Cacheable @Cacheable} annotation, this annotation * does not cause the advised method to be skipped. Rather, it always causes the - * method to be invoked and its result to be stored in the associated cache. Note + * method to be invoked and its result to be stored in the associated cache if the + * {@link #condition()} and {@link #unless()} expressions match accordingly. Note * that Java8's {@code Optional} return types are automatically handled and its * content is stored in the cache if present. * @@ -118,10 +119,15 @@ /** * Spring Expression Language (SpEL) expression used for making the cache * put operation conditional. + *

This expression is evaluated after the method has been called due to the + * nature of the put operation and can therefore refer to the {@code result}. *

Default is {@code ""}, meaning the method result is always cached. *

The SpEL expression evaluates against a dedicated context that provides the * following meta-data: *