Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Buildmaster 7c2a72c9b4 Release v5.3.5 2021-03-16 08:03:00 +00:00
212 changed files with 1513 additions and 4103 deletions
+31 -29
View File
@@ -1,7 +1,7 @@
plugins {
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
id 'io.spring.nohttp' version '0.0.5.RELEASE'
id 'org.jetbrains.kotlin.jvm' version '1.5.0' apply false
id 'org.jetbrains.kotlin.jvm' version '1.4.31' apply false
id 'org.jetbrains.dokka' version '0.10.1' apply false
id 'org.asciidoctor.jvm.convert' version '3.1.0'
id 'org.asciidoctor.jvm.pdf' version '3.1.0'
@@ -9,9 +9,8 @@ plugins {
id "io.freefair.aspectj" version '5.1.1' apply false
id "com.github.ben-manes.versions" version '0.28.0'
id "com.github.johnrengelman.shadow" version "6.1.0" apply false
id "me.champeau.jmh" version "0.6.4" apply false
id "org.jetbrains.kotlin.plugin.serialization" version "1.5.0" apply false
id "org.unbroken-dome.xjc" version '2.0.0' apply false
id "me.champeau.gradle.jmh" version "0.5.2" apply false
id "org.jetbrains.kotlin.plugin.serialization" version "1.4.31" apply false
}
ext {
@@ -27,19 +26,18 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.3"
mavenBom "io.netty:netty-bom:4.1.63.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.7"
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.2"
mavenBom "io.netty:netty-bom:4.1.60.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.5"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR9"
mavenBom "io.rsocket:rsocket-bom:1.1.0"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.40.v20210413"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.0"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.38.v20210224"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.30"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.3"
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.0"
mavenBom "org.junit:junit-bom:5.7.1"
}
dependencies {
dependencySet(group: 'org.apache.logging.log4j', version: '2.14.1') {
dependencySet(group: 'org.apache.logging.log4j', version: '2.14.0') {
entry 'log4j-api'
entry 'log4j-core'
entry 'log4j-jul'
@@ -56,7 +54,7 @@ configure(allprojects) { project ->
entry 'aspectjtools'
entry 'aspectjweaver'
}
dependencySet(group: 'org.codehaus.groovy', version: '3.0.8') {
dependencySet(group: 'org.codehaus.groovy', version: '3.0.7') {
entry 'groovy'
entry 'groovy-jsr223'
entry 'groovy-templates' // requires findbugs for warning-free compilation
@@ -67,18 +65,18 @@ configure(allprojects) { project ->
dependency "io.reactivex:rxjava:1.3.8"
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
dependency "io.reactivex.rxjava3:rxjava:3.0.12"
dependency "io.reactivex.rxjava3:rxjava:3.0.11"
dependency "io.projectreactor.tools:blockhound:1.0.4.RELEASE"
dependency "com.caucho:hessian:4.0.63"
dependency "com.fasterxml:aalto-xml:1.2.2"
dependency("com.fasterxml.woodstox:woodstox-core:6.2.6") {
dependency("com.fasterxml.woodstox:woodstox-core:6.2.4") {
exclude group: "stax", name: "stax-api"
}
dependency "com.google.code.gson:gson:2.8.6"
dependency "com.google.protobuf:protobuf-java-util:3.15.8"
dependency "com.google.protobuf:protobuf-java-util:3.15.5"
dependency "com.googlecode.protobuf-java-format:protobuf-java-format:1.4"
dependency("com.thoughtworks.xstream:xstream:1.4.16") {
dependency("com.thoughtworks.xstream:xstream:1.4.15") {
exclude group: "xpp3", name: "xpp3_min"
exclude group: "xmlpull", name: "xmlpull"
}
@@ -92,10 +90,14 @@ configure(allprojects) { project ->
}
dependency "org.ogce:xpp3:1.1.6"
dependency "org.yaml:snakeyaml:1.28"
dependencySet(group: 'org.jetbrains.kotlinx', version: '1.0.1') {
entry 'kotlinx-serialization-core'
entry 'kotlinx-serialization-json'
}
dependency "com.h2database:h2:1.4.200"
dependency "com.github.ben-manes.caffeine:caffeine:2.9.1"
dependency "com.github.librepdf:openpdf:1.3.26"
dependency "com.github.ben-manes.caffeine:caffeine:2.9.0"
dependency "com.github.librepdf:openpdf:1.3.25"
dependency "com.rometools:rome:1.15.0"
dependency "commons-io:commons-io:2.5"
dependency "io.vavr:vavr:0.10.3"
@@ -115,30 +117,30 @@ configure(allprojects) { project ->
}
dependency "org.apache.poi:poi-ooxml:4.1.2"
dependency "org.apache-extras.beanshell:bsh:2.0b6"
dependency "org.freemarker:freemarker:2.3.31"
dependency "org.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.31.Final"
dependency "org.hibernate:hibernate-core:5.4.29.Final"
dependency "org.hibernate:hibernate-validator:6.2.0.Final"
dependency "org.webjars:webjars-locator-core:0.46"
dependency "org.webjars:underscorejs:1.8.3"
dependencySet(group: 'org.apache.tomcat', version: '9.0.45') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.43') {
entry 'tomcat-util'
entry('tomcat-websocket') {
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
}
}
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.45') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.43') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.7.Final') {
dependencySet(group: 'io.undertow', version: '2.2.5.Final') {
entry 'undertow-core'
entry('undertow-websockets-jsr') {
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
@@ -186,7 +188,7 @@ configure(allprojects) { project ->
dependency("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1") {
exclude group: "junit", name: "junit"
}
dependency "org.testng:testng:7.4.0"
dependency "org.testng:testng:7.3.0"
dependency "org.hamcrest:hamcrest:2.1"
dependency "org.awaitility:awaitility:3.1.6"
dependency "org.assertj:assertj-core:3.19.0"
@@ -196,7 +198,7 @@ configure(allprojects) { project ->
exclude group: "org.hamcrest", name: "hamcrest-core"
}
}
dependencySet(group: 'org.mockito', version: '3.9.0') {
dependencySet(group: 'org.mockito', version: '3.8.0') {
entry('mockito-core') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
@@ -204,10 +206,10 @@ configure(allprojects) { project ->
}
dependency "io.mockk:mockk:1.10.2"
dependency("net.sourceforge.htmlunit:htmlunit:2.49.1") {
dependency("net.sourceforge.htmlunit:htmlunit:2.47.1") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.49.1") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.47.1") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
@@ -316,7 +318,7 @@ configure([rootProject] + javaProjects) { project ->
kotlinOptions {
languageVersion = "1.3"
apiVersion = "1.3"
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
freeCompilerArgs = ["-Xjsr305=strict"]
allWarningsAsErrors = true
}
}
@@ -336,7 +338,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "8.42"
toolVersion = "8.41"
configDirectory.set(rootProject.file("src/checkstyle"))
}
+1 -1
View File
@@ -14,7 +14,7 @@ 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
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.3.0/concourse-release-scripts-0.3.0.jar
###########################################################
# JAVA
+1 -1
View File
@@ -5,7 +5,7 @@ github-repo: "https://github.com/spring-projects/spring-framework.git"
github-repo-name: "spring-projects/spring-framework"
docker-hub-organization: "springci"
artifactory-server: "https://repo.spring.io"
branch: "main"
branch: "master"
milestone: "5.3.x"
build-name: "spring-framework"
pipeline-name: "spring-framework"
+11 -59
View File
@@ -9,8 +9,8 @@ anchors:
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_USER_TOKEN: ((sonatype-user-token))
SONATYPE_PASSWORD_TOKEN: ((sonatype-user-token-password))
SONATYPE_URL: ((sonatype-url))
SONATYPE_STAGING_PROFILE_ID: ((sonatype-staging-profile-id))
artifactory-task-params: &artifactory-task-params
@@ -18,6 +18,9 @@ anchors:
ARTIFACTORY_USERNAME: ((artifactory-username))
ARTIFACTORY_PASSWORD: ((artifactory-password))
build-project-task-params: &build-project-task-params
privileged: true
timeout: ((task-timeout))
params:
BRANCH: ((branch))
<<: *gradle-enterprise-task-params
docker-resource-source: &docker-resource-source
@@ -51,11 +54,6 @@ resource_types:
source:
repository: dpb587/github-status-resource
tag: master
- name: pull-request
type: registry-image
source:
repository: teliaoss/github-pr-resource
tag: v0.23.0
- name: slack-notification
type: registry-image
source:
@@ -95,14 +93,6 @@ resources:
username: ((artifactory-username))
password: ((artifactory-password))
build_name: ((build-name))
- name: git-pull-request
type: pull-request
icon: source-pull
source:
access_token: ((github-ci-pull-request-token))
repository: ((github-repo-name))
base_branch: ((branch))
ignore_paths: ["ci/*"]
- name: repo-status-build
type: github-status-resource
icon: eye-check-outline
@@ -172,10 +162,7 @@ jobs:
- task: build-project
image: ci-image
file: git-repo/ci/tasks/build-project.yml
privileged: true
timeout: ((task-timeout))
params:
<<: *build-project-task-params
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-build
@@ -230,11 +217,10 @@ jobs:
- task: check-project
image: ci-image
file: git-repo/ci/tasks/check-project.yml
privileged: true
timeout: ((task-timeout))
params:
MAIN_TOOLCHAIN: 8
TEST_TOOLCHAIN: 11
<<: *build-project-task-params
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk11-build
@@ -258,11 +244,10 @@ jobs:
- task: check-project
image: ci-image
file: git-repo/ci/tasks/check-project.yml
privileged: true
timeout: ((task-timeout))
params:
MAIN_TOOLCHAIN: 8
TEST_TOOLCHAIN: 15
<<: *build-project-task-params
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk15-build
@@ -272,37 +257,6 @@ jobs:
<<: *slack-fail-params
- put: repo-status-jdk15-build
params: { state: "success", commit: "git-repo" }
- name: build-pull-requests
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
resource: git-pull-request
trigger: true
version: every
- do:
- put: git-pull-request
params:
path: git-repo
status: pending
- task: build-pr
image: ci-image
file: git-repo/ci/tasks/build-pr.yml
privileged: true
timeout: ((task-timeout))
params:
<<: *build-project-task-params
on_success:
put: git-pull-request
params:
path: git-repo
status: success
on_failure:
put: git-pull-request
params:
path: git-repo
status: failure
- name: stage-milestone
serial: true
plan:
@@ -422,7 +376,7 @@ jobs:
trigger: false
passed: [stage-release]
params:
download_artifacts: true
download_artifacts: false
save_build_info: true
- task: promote
image: ci-image
@@ -458,5 +412,3 @@ groups:
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
- name: "ci-images"
jobs: ["build-ci-images"]
- name: "pull-requests"
jobs: [ "build-pull-requests" ]
-8
View File
@@ -1,8 +0,0 @@
#!/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
+2 -2
View File
@@ -4,6 +4,6 @@ set -e
source $(dirname $0)/common.sh
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK11,JDK15 \
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Dorg.gradle.java.installations.fromEnv=JDK11,JDK15 \
-PmainToolchain=$MAIN_TOOLCHAIN -PtestToolchain=$TEST_TOOLCHAIN --no-daemon --max-workers=4 check
popd > /dev/null
-19
View File
@@ -1,19 +0,0 @@
---
platform: linux
inputs:
- name: git-repo
caches:
- path: gradle
params:
BRANCH:
CI: true
GRADLE_ENTERPRISE_ACCESS_KEY:
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
run:
path: bash
args:
- -ec
- |
${PWD}/git-repo/ci/scripts/build-pr.sh
+1 -1
View File
@@ -1,7 +1,7 @@
---
platform: linux
image_resource:
type: registry-image
type: docker-image
source:
repository: springio/github-changelog-generator
tag: '0.0.6'
+2 -2
View File
@@ -10,8 +10,8 @@ params:
ARTIFACTORY_SERVER:
ARTIFACTORY_USERNAME:
ARTIFACTORY_PASSWORD:
SONATYPE_USER:
SONATYPE_PASSWORD:
SONATYPE_USER_TOKEN:
SONATYPE_PASSWORD_TOKEN:
SONATYPE_URL:
SONATYPE_STAGING_PROFILE_ID:
run:
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.3.7
version=5.3.5
org.gradle.jvmargs=-Xmx1536M
org.gradle.caching=true
org.gradle.parallel=true
+18
View File
@@ -108,3 +108,21 @@ task eclipseBuildship(type: Copy) {
tasks["eclipseJdt"].dependsOn(eclipseJdtPrepare)
tasks["cleanEclipse"].dependsOn(cleanEclipseJdtUi)
tasks["eclipse"].dependsOn(eclipseSettings, eclipseWstComponent)
// Filter 'build' folder
eclipse.project.file.withXml {
def node = it.asNode()
def filteredResources = node.get("filteredResources")
if(filteredResources) {
node.remove(filteredResources)
}
def filterNode = node.appendNode("filteredResources").appendNode("filter")
filterNode.appendNode("id", "1359048889071")
filterNode.appendNode("name", "")
filterNode.appendNode("type", "30")
def matcherNode = filterNode.appendNode("matcher")
matcherNode.appendNode("id", "org.eclipse.ui.ide.multiFilter")
matcherNode.appendNode("arguments", "1.0-projectRelativePath-matches-false-false-build")
}
+3 -3
View File
@@ -4,12 +4,12 @@ apply plugin: 'org.springframework.build.optional-dependencies'
// Uncomment the following for Shadow support in the jmhJar block.
// Currently commented out due to ZipException: archive is not a ZIP archive
// apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'me.champeau.jmh'
apply plugin: 'me.champeau.gradle.jmh'
apply from: "$rootDir/gradle/publications.gradle"
dependencies {
jmh 'org.openjdk.jmh:jmh-core:1.28'
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.28'
jmh 'org.openjdk.jmh:jmh-core:1.25'
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.25'
jmh 'net.sf.jopt-simple:jopt-simple:4.6'
}
+21 -76
View File
@@ -11,8 +11,6 @@
* <li>a JDK11 toolchain for compiling and running the test SourceSet
* </ul>
*
* By default, the build will fall back to using the current JDK and 1.8 language level for all sourceSets.
*
* Gradle will automatically detect JDK distributions in well-known locations.
* The following command will list the detected JDKs on the host.
* {@code
@@ -25,41 +23,21 @@
* /opt/openjdk/java11
* $ echo JDK15
* /opt/openjdk/java15
* $ ./gradlew -Porg.gradle.java.installations.fromEnv=JDK11,JDK15 check
* $ ./gradlew -Dorg.gradle.java.installations.fromEnv=JDK11,JDK15 check
* }
*
* @author Brian Clozel
* @author Sam Brannen
*/
def mainToolchainConfigured() {
return project.hasProperty('mainToolchain') && project.mainToolchain
}
def testToolchainConfigured() {
return project.hasProperty('testToolchain') && project.testToolchain
}
def mainToolchainLanguageVersion() {
if (mainToolchainConfigured()) {
return JavaLanguageVersion.of(project.mainToolchain.toString())
}
return JavaLanguageVersion.of(8)
}
def testToolchainLanguageVersion() {
if (testToolchainConfigured()) {
return JavaLanguageVersion.of(project.testToolchain.toString())
}
return mainToolchainLanguageVersion()
}
def mainToolchain = 'mainToolchain'
def testToolchain = 'testToolchain'
plugins.withType(JavaPlugin) {
// Configure the Java Toolchain if the 'mainToolchain' is configured
if (mainToolchainConfigured()) {
// Configure the Java Toolchain if the 'mainToolchain' property is defined
if (project.hasProperty(mainToolchain)) {
def mainLanguageVersion = JavaLanguageVersion.of(project.property(mainToolchain).toString())
java {
toolchain {
languageVersion = mainToolchainLanguageVersion()
languageVersion = mainLanguageVersion
}
}
}
@@ -70,8 +48,8 @@ plugins.withType(JavaPlugin) {
}
}
// Configure a specific Java Toolchain for compiling and running tests if the 'testToolchain' property is defined
if (testToolchainConfigured()) {
def testLanguageVersion = testToolchainLanguageVersion()
if (project.hasProperty(testToolchain)) {
def testLanguageVersion = JavaLanguageVersion.of(project.property(testToolchain).toString());
tasks.withType(JavaCompile).matching { it.name.contains("Test") }.configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = testLanguageVersion
@@ -87,17 +65,17 @@ plugins.withType(JavaPlugin) {
plugins.withType(GroovyPlugin) {
// Fallback to JDK8
if (!mainToolchainConfigured()) {
if (!project.hasProperty(mainToolchain)) {
compileGroovy {
sourceCompatibility = JavaVersion.VERSION_1_8
}
}
}
// Configure the Kotlin compiler if the 'mainToolchain' property is defined
pluginManager.withPlugin("kotlin") {
// Configure the Kotlin compiler if the 'mainToolchain' property is defined
if (mainToolchainConfigured()) {
def mainLanguageVersion = mainToolchainLanguageVersion()
if (project.hasProperty(mainToolchain)) {
def mainLanguageVersion = JavaLanguageVersion.of(project.property(mainToolchain).toString());
def compiler = javaToolchains.compilerFor {
languageVersion = mainLanguageVersion
}
@@ -118,21 +96,15 @@ pluginManager.withPlugin("kotlin") {
}
}
else {
// Fallback to JDK8
compileKotlin {
kotlinOptions {
jvmTarget = '1.8'
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = '1.8'
}
}
}
if (testToolchainConfigured()) {
def testLanguageVersion = testToolchainLanguageVersion()
if (project.hasProperty(testToolchain)) {
def testLanguageVersion = JavaLanguageVersion.of(project.property(testToolchain).toString());
def compiler = javaToolchains.compilerFor {
languageVersion = testLanguageVersion
}
@@ -145,38 +117,11 @@ pluginManager.withPlugin("kotlin") {
}
}
}
}
// Configure the JMH plugin to use the toolchain for generating and running JMH bytecode
pluginManager.withPlugin("me.champeau.jmh") {
if (mainToolchainConfigured() || testToolchainConfigured()) {
tasks.matching { it.name.contains('jmh') && it.hasProperty('javaLauncher') }.configureEach {
javaLauncher.set(javaToolchains.launcherFor {
languageVersion.set(testToolchainLanguageVersion())
})
}
tasks.withType(JavaCompile).matching { it.name.contains("Jmh") }.configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = testToolchainLanguageVersion()
else {
compileTestKotlin {
kotlinOptions {
jvmTarget = '1.8'
}
}
}
}
// Store resolved Toolchain JVM information as custom values in the build scan.
rootProject.ext {
resolvedMainToolchain = false
resolvedTestToolchain = false
}
gradle.taskGraph.afterTask { Task task, TaskState state ->
if (mainToolchainConfigured() && !resolvedMainToolchain && task instanceof JavaCompile && task.javaCompiler.isPresent()) {
def metadata = task.javaCompiler.get().metadata
task.project.buildScan.value('Main toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
resolvedMainToolchain = true
}
if (testToolchainConfigured() && !resolvedTestToolchain && task instanceof Test && task.javaLauncher.isPresent()) {
def metadata = task.javaLauncher.get().metadata
task.project.buildScan.value('Test toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
resolvedTestToolchain = true
}
}
}
+7 -1
View File
@@ -6,7 +6,7 @@ pluginManagement {
}
plugins {
id "com.gradle.enterprise" version "3.6.1"
id "com.gradle.enterprise" version "3.5.1"
id "io.spring.ge.conventions" version "0.0.7"
}
@@ -45,6 +45,12 @@ rootProject.children.each {project ->
settings.gradle.projectsLoaded {
gradleEnterprise {
buildScan {
if (settings.gradle.rootProject.hasProperty('mainToolchain')) {
value("Main toolchain", 'JDK' + settings.gradle.rootProject.getProperty('mainToolchain'))
}
if (settings.gradle.rootProject.hasProperty('testToolchain')) {
value("Test toolchain", 'JDK' + settings.gradle.rootProject.getProperty('testToolchain'))
}
File buildDir = settings.gradle.rootProject.getBuildDir()
buildDir.mkdirs()
new File(buildDir, "build-scan-uri.txt").text = "(build scan not generated)"
@@ -510,7 +510,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
if (specificInterceptors.length > 0) {
// specificInterceptors may equal PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
// specificInterceptors may equals PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
allInterceptors.addAll(Arrays.asList(specificInterceptors));
}
if (commonInterceptors.length > 0) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,9 +23,9 @@ import org.springframework.util.StringUtils;
/**
* Editor for {@code java.util.Locale}, to directly populate a Locale property.
*
* <p>Expects the same syntax as Locale's {@code toString()}, i.e. language +
* <p>Expects the same syntax as Locale's {@code toString}, i.e. language +
* optionally country + optionally variant, separated by "_" (e.g. "en", "en_US").
* Also accepts spaces as separators, as an alternative to underscores.
* Also accepts spaces as separators, as alternative to underscores.
*
* @author Juergen Hoeller
* @since 26.05.2003
@@ -26,8 +26,8 @@ import java.nio.file.Paths;
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 class PathEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
boolean nioPathCandidate = !text.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX);
boolean nioPathCandidate = !text.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX);
if (nioPathCandidate && !text.startsWith("/")) {
try {
URI uri = new URI(text);
@@ -85,13 +85,9 @@ public class PathEditor extends PropertyEditorSupport {
return;
}
}
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
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
// protocol handlers via Spring's resource mechanism).
}
}
@@ -101,7 +97,8 @@ public class PathEditor extends PropertyEditorSupport {
if (resource == null) {
setValue(null);
}
else if (nioPathCandidate && !resource.exists()) {
else if (!resource.isFile() && !resource.exists() && nioPathCandidate) {
// Prefer getFile().toPath() below for non-existent file handles
setValue(Paths.get(text).normalize());
}
else {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,6 +44,8 @@ public class PropertyComparator<T> implements Comparator<T> {
private final SortDefinition sortDefinition;
private final BeanWrapperImpl beanWrapper = new BeanWrapperImpl(false);
/**
* Create a new PropertyComparator for the given SortDefinition.
@@ -113,9 +115,8 @@ public class PropertyComparator<T> implements Comparator<T> {
// (similar to JSTL EL). If the property doesn't exist in the
// first place, let the exception through.
try {
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(false);
beanWrapper.setWrappedInstance(obj);
return beanWrapper.getPropertyValue(this.sortDefinition.getProperty());
this.beanWrapper.setWrappedInstance(obj);
return this.beanWrapper.getPropertyValue(this.sortDefinition.getProperty());
}
catch (BeansException ex) {
logger.debug("PropertyComparator could not access property - treating as null for sorting", ex);
@@ -39,7 +39,8 @@ public class PathEditorTests {
pathEditor.setAsText("classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" +
ClassUtils.getShortName(getClass()) + ".class");
Object value = pathEditor.getValue();
assertThat(value instanceof Path).isTrue();
boolean condition = value instanceof Path;
assertThat(condition).isTrue();
Path path = (Path) value;
assertThat(path.toFile().exists()).isTrue();
}
@@ -56,9 +57,11 @@ public class PathEditorTests {
PropertyEditor pathEditor = new PathEditor();
pathEditor.setAsText("file:/no_way_this_file_is_found.doc");
Object value = pathEditor.getValue();
assertThat(value instanceof Path).isTrue();
boolean condition1 = value instanceof Path;
assertThat(condition1).isTrue();
Path path = (Path) value;
assertThat(!path.toFile().exists()).isTrue();
boolean condition = !path.toFile().exists();
assertThat(condition).isTrue();
}
@Test
@@ -66,9 +69,11 @@ public class PathEditorTests {
PropertyEditor pathEditor = new PathEditor();
pathEditor.setAsText("/no_way_this_file_is_found.doc");
Object value = pathEditor.getValue();
assertThat(value instanceof Path).isTrue();
boolean condition1 = value instanceof Path;
assertThat(condition1).isTrue();
Path path = (Path) value;
assertThat(!path.toFile().exists()).isTrue();
boolean condition = !path.toFile().exists();
assertThat(condition).isTrue();
}
@Test
@@ -76,26 +81,23 @@ public class PathEditorTests {
PropertyEditor pathEditor = new PathEditor();
pathEditor.setAsText("C:\\no_way_this_file_is_found.doc");
Object value = pathEditor.getValue();
assertThat(value instanceof Path).isTrue();
boolean condition1 = value instanceof Path;
assertThat(condition1).isTrue();
Path path = (Path) value;
assertThat(!path.toFile().exists()).isTrue();
boolean condition = !path.toFile().exists();
assertThat(condition).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;
}
}
pathEditor.setAsText("file://C:\\no_way_this_file_is_found.doc");
Object value = pathEditor.getValue();
boolean condition1 = value instanceof Path;
assertThat(condition1).isTrue();
Path path = (Path) value;
boolean condition = !path.toFile().exists();
assertThat(condition).isTrue();
}
@Test
@@ -105,7 +107,8 @@ public class PathEditorTests {
ClassUtils.getShortName(getClass()) + ".class";
pathEditor.setAsText(fileName);
Object value = pathEditor.getValue();
assertThat(value instanceof Path).isTrue();
boolean condition = value instanceof Path;
assertThat(condition).isTrue();
Path path = (Path) value;
File file = path.toFile();
assertThat(file.exists()).isTrue();
@@ -123,7 +126,8 @@ public class PathEditorTests {
ClassUtils.getShortName(getClass()) + ".clazz";
pathEditor.setAsText(fileName);
Object value = pathEditor.getValue();
assertThat(value instanceof Path).isTrue();
boolean condition = value instanceof Path;
assertThat(condition).isTrue();
Path path = (Path) value;
File file = path.toFile();
assertThat(file.exists()).isFalse();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,6 +19,7 @@ package org.springframework.context.index.processor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -45,6 +46,9 @@ import javax.lang.model.element.TypeElement;
*/
public class CandidateComponentsIndexer implements Processor {
private static final Set<ElementKind> TYPE_KINDS =
Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS, ElementKind.INTERFACE));
private MetadataStore metadataStore;
private MetadataCollector metadataCollector;
@@ -132,8 +136,7 @@ public class CandidateComponentsIndexer implements Processor {
private static List<TypeElement> staticTypesIn(Iterable<? extends Element> elements) {
List<TypeElement> list = new ArrayList<>();
for (Element element : elements) {
if ((element.getKind().isClass() || element.getKind() == ElementKind.INTERFACE) &&
element.getModifiers().contains(Modifier.STATIC) && element instanceof TypeElement) {
if (TYPE_KINDS.contains(element.getKind()) && element.getModifiers().contains(Modifier.STATIC)) {
list.add((TypeElement) element);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ class IndexedStereotypesProvider implements StereotypesProvider {
public Set<String> getStereotypes(Element element) {
Set<String> stereotypes = new LinkedHashSet<>();
ElementKind kind = element.getKind();
if (!kind.isClass() && kind != ElementKind.INTERFACE) {
if (kind != ElementKind.CLASS && kind != ElementKind.INTERFACE) {
return stereotypes;
}
Set<Element> seen = new HashSet<>();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -130,8 +130,8 @@ public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, Ini
@Override
public void afterPropertiesSet() throws CacheException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing EhCache CacheManager" +
if (logger.isInfoEnabled()) {
logger.info("Initializing EhCache CacheManager" +
(this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : ""));
}
@@ -188,8 +188,8 @@ public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, Ini
@Override
public void destroy() {
if (this.cacheManager != null && this.locallyManaged) {
if (logger.isDebugEnabled()) {
logger.debug("Shutting down EhCache CacheManager" +
if (logger.isInfoEnabled()) {
logger.info("Shutting down EhCache CacheManager" +
(this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : ""));
}
this.cacheManager.shutdown();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -221,11 +221,11 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
}
catch (NoUniqueBeanDefinitionException ex) {
throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " +
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.", ex);
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.");
}
catch (NoSuchBeanDefinitionException ex) {
throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " +
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.", ex);
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.");
}
}
this.initialized = true;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,18 +57,17 @@ public abstract class MessageSourceSupport {
/**
* Set whether to always apply the {@code MessageFormat} rules, parsing even
* messages without arguments.
* <p>Default is {@code false}: Messages without arguments are by default
* returned as-is, without parsing them through {@code MessageFormat}.
* Set this to {@code true} to enforce {@code MessageFormat} for all messages,
* expecting all message texts to be written with {@code MessageFormat} escaping.
* <p>For example, {@code MessageFormat} expects a single quote to be escaped
* as two adjacent single quotes ({@code "''"}). If your message texts are all
* written with such escaping, even when not defining argument placeholders,
* you need to set this flag to {@code true}. Otherwise, only message texts
* with actual arguments are supposed to be written with {@code MessageFormat}
* escaping.
* Set whether to always apply the {@code MessageFormat} rules,
* parsing even messages without arguments.
* <p>Default is "false": Messages without arguments are by default
* returned as-is, without parsing them through MessageFormat.
* Set this to "true" to enforce MessageFormat for all messages,
* expecting all message texts to be written with MessageFormat escaping.
* <p>For example, MessageFormat expects a single quote to be escaped
* as "''". If your message texts are all written with such escaping,
* even when not defining argument placeholders, you need to set this
* flag to "true". Else, only message texts with actual arguments
* are supposed to be written with MessageFormat escaping.
* @see java.text.MessageFormat
*/
public void setAlwaysUseMessageFormat(boolean alwaysUseMessageFormat) {
@@ -76,7 +75,7 @@ public abstract class MessageSourceSupport {
}
/**
* Return whether to always apply the {@code MessageFormat} rules, parsing even
* Return whether to always apply the MessageFormat rules, parsing even
* messages without arguments.
*/
protected boolean isAlwaysUseMessageFormat() {
@@ -151,10 +150,10 @@ public abstract class MessageSourceSupport {
}
/**
* Create a {@code MessageFormat} for the given message and Locale.
* @param msg the message to create a {@code MessageFormat} for
* @param locale the Locale to create a {@code MessageFormat} for
* @return the {@code MessageFormat} instance
* Create a MessageFormat for the given message and Locale.
* @param msg the message to create a MessageFormat for
* @param locale the Locale to create a MessageFormat for
* @return the MessageFormat instance
*/
protected MessageFormat createMessageFormat(String msg, Locale locale) {
return new MessageFormat(msg, locale);
@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
*
* <p>Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
* Can be applied to {@link java.util.Date}, {@link java.util.Calendar}, {@link Long} (for
* millisecond timestamps) as well as JSR-310 {@code java.time} value types.
* millisecond timestamps) as well as JSR-310 {@code java.time} and Joda-Time value types.
*
* <p>For style-based formatting, set the {@link #style} attribute to the desired style pattern code.
* The first character of the code is the date style, and the second character is the time style.
@@ -219,11 +219,9 @@ public class DateFormatter implements Formatter<Date> {
}
}
if (this.source != null) {
ParseException parseException = new ParseException(
throw new ParseException(
String.format("Unable to parse date time value \"%s\" using configuration from %s", text, this.source),
ex.getErrorOffset());
parseException.initCause(ex);
throw parseException;
}
// else rethrow original exception
throw ex;
@@ -101,7 +101,7 @@ public final class TemporalAccessorParser implements Parser<TemporalAccessor> {
if (this.source != null) {
throw new DateTimeParseException(
String.format("Unable to parse date time value \"%s\" using configuration from %s", text, this.source),
text, ex.getErrorIndex(), ex);
text, ex.getErrorIndex());
}
// else rethrow original exception
throw ex;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -177,8 +177,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
* Set up the ExecutorService.
*/
public void initialize() {
if (logger.isDebugEnabled()) {
logger.debug("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
if (logger.isInfoEnabled()) {
logger.info("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (!this.threadNamePrefixSet && this.beanName != null) {
setThreadNamePrefix(this.beanName + "-");
@@ -214,8 +214,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
* @see java.util.concurrent.ExecutorService#shutdownNow()
*/
public void shutdown() {
if (logger.isDebugEnabled()) {
logger.debug("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
if (logger.isInfoEnabled()) {
logger.info("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (this.executor != null) {
if (this.waitForTasksToCompleteOnShutdown) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -157,11 +157,6 @@ abstract class CronField {
return this.type;
}
@SuppressWarnings("unchecked")
protected static <T extends Temporal & Comparable<? super T>> T cast(Temporal temporal) {
return (T) temporal;
}
/**
* Represents the type of cron field, i.e. seconds, minutes, hours,
@@ -241,17 +236,11 @@ abstract class CronField {
*/
public <T extends Temporal & Comparable<? super T>> T elapseUntil(T temporal, int goal) {
int current = get(temporal);
ValueRange range = temporal.range(this.field);
if (current < goal) {
if (range.isValidIntValue(goal)) {
return cast(temporal.with(this.field, goal));
}
else {
// goal is invalid, eg. 29th Feb, lets try to get as close as possible
return this.field.getBaseUnit().addTo(temporal, goal - current);
}
return this.field.getBaseUnit().addTo(temporal, goal - current);
}
else {
ValueRange range = temporal.range(this.field);
long amount = goal + range.getMaximum() - current + 1 - range.getMinimum();
return this.field.getBaseUnit().addTo(temporal, amount);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -326,6 +326,12 @@ final class QuartzCronField extends CronField {
}
}
@SuppressWarnings("unchecked")
private static <T extends Temporal & Comparable<? super T>> T cast(Temporal temporal) {
return (T) temporal;
}
@Override
public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
T result = adjust(temporal);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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 class ConcurrentModel extends ConcurrentHashMap<String, Object> implement
@Override
@Nullable
public Object put(String key, @Nullable Object value) {
public Object put(String key, Object value) {
if (value != null) {
return super.put(key, value);
}
@@ -1,70 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.validation.annotation;
import java.lang.annotation.Annotation;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
/**
* Utility class for handling validation annotations.
* Mainly for internal use within the framework.
*
* @author Christoph Dreis
* @since 5.3.7
*/
public abstract class ValidationAnnotationUtils {
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/**
* Determine any validation hints by the given annotation.
* <p>This implementation checks for {@code @javax.validation.Valid},
* Spring's {@link org.springframework.validation.annotation.Validated},
* and custom annotations whose name starts with "Valid".
* @param ann the annotation (potentially a validation annotation)
* @return the validation hints to apply (possibly an empty array),
* or {@code null} if this annotation does not trigger any validation
*/
@Nullable
public static Object[] determineValidationHints(Annotation ann) {
Class<? extends Annotation> annotationType = ann.annotationType();
String annotationName = annotationType.getName();
if ("javax.validation.Valid".equals(annotationName)) {
return EMPTY_OBJECT_ARRAY;
}
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
if (validatedAnn != null) {
Object hints = validatedAnn.value();
return convertValidationHints(hints);
}
if (annotationType.getSimpleName().startsWith("Valid")) {
Object hints = AnnotationUtils.getValue(ann);
return convertValidationHints(hints);
}
return null;
}
private static Object[] convertValidationHints(@Nullable Object hints) {
if (hints == null) {
return EMPTY_OBJECT_ARRAY;
}
return (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,8 +19,6 @@ package org.springframework.cache.config;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
@@ -89,7 +87,6 @@ public class EnableCachingTests extends AbstractCacheAnnotationTests {
}
catch (IllegalStateException ex) {
assertThat(ex.getMessage().contains("no unique bean of type CacheManager")).isTrue();
assertThat(ex).hasCauseInstanceOf(NoUniqueBeanDefinitionException.class);
}
}
@@ -124,7 +121,6 @@ public class EnableCachingTests extends AbstractCacheAnnotationTests {
}
catch (IllegalStateException ex) {
assertThat(ex.getMessage().contains("no bean of type CacheManager")).isTrue();
assertThat(ex).hasCauseInstanceOf(NoSuchBeanDefinitionException.class);
}
}
@@ -119,39 +119,6 @@ public class DateFormattingTests {
assertThat(binder.getBindingResult().getFieldValue("styleDate")).isEqualTo("10/31/09");
}
@Test
void styleDateWithInvalidFormat() {
String propertyName = "styleDate";
String propertyValue = "99/01/01";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(1);
FieldError fieldError = bindingResult.getFieldError(propertyName);
TypeMismatchException exception = fieldError.unwrap(TypeMismatchException.class);
assertThat(exception)
.hasMessageContaining("for property 'styleDate'")
.hasCauseInstanceOf(ConversionFailedException.class).getCause()
.hasMessageContaining("for value '99/01/01'")
.hasCauseInstanceOf(IllegalArgumentException.class).getCause()
.hasMessageContaining("Parse attempt failed for value [99/01/01]")
.hasCauseInstanceOf(ParseException.class).getCause()
// Unable to parse date time value "99/01/01" using configuration from
// @org.springframework.format.annotation.DateTimeFormat(pattern=, style=S-, iso=NONE, fallbackPatterns=[])
// We do not check "fallbackPatterns=[]", since the array representation in the toString()
// implementation for annotations changed from [] to {} in Java 9. In addition, strings
// are enclosed in double quotes beginning with Java 9. Thus, we cannot check directly
// for the presence of "style=S-".
.hasMessageContainingAll(
"Unable to parse date time value \"99/01/01\" using configuration from",
"@org.springframework.format.annotation.DateTimeFormat",
"style=", "S-", "iso=NONE")
.hasCauseInstanceOf(ParseException.class).getCause()
.hasMessageStartingWith("Unparseable date: \"99/01/01\"")
.hasNoCause();
}
@Test
void testBindDateArray() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
@@ -363,10 +330,7 @@ public class DateFormattingTests {
.hasMessageContainingAll(
"Unable to parse date time value \"210302\" using configuration from",
"@org.springframework.format.annotation.DateTimeFormat",
"yyyy-MM-dd", "M/d/yy", "yyyyMMdd", "yyyy.MM.dd")
.hasCauseInstanceOf(ParseException.class).getCause()
.hasMessageStartingWith("Unparseable date: \"210302\"")
.hasNoCause();
"yyyy-MM-dd", "M/d/yy", "yyyyMMdd", "yyyy.MM.dd");
}
}
@@ -16,7 +16,6 @@
package org.springframework.format.datetime.standard;
import java.time.DateTimeException;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
@@ -321,36 +320,6 @@ class DateTimeFormattingTests {
assertThat(binder.getBindingResult().getFieldValue("isoLocalDate")).isEqualTo("2009-10-31");
}
@Test
void isoLocalDateWithInvalidFormat() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
String propertyName = "isoLocalDate";
propertyValues.add(propertyName, "2009-31-10");
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(1);
FieldError fieldError = bindingResult.getFieldError(propertyName);
assertThat(fieldError.unwrap(TypeMismatchException.class))
.hasMessageContaining("for property 'isoLocalDate'")
.hasCauseInstanceOf(ConversionFailedException.class).getCause()
.hasMessageContaining("for value '2009-31-10'")
.hasCauseInstanceOf(IllegalArgumentException.class).getCause()
.hasMessageContaining("Parse attempt failed for value [2009-31-10]")
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
// Unable to parse date time value "2009-31-10" using configuration from
// @org.springframework.format.annotation.DateTimeFormat(pattern=, style=SS, iso=DATE, fallbackPatterns=[])
// We do not check "fallbackPatterns=[]", since the array representation in the toString()
// implementation for annotations changed from [] to {} in Java 9.
.hasMessageContainingAll(
"Unable to parse date time value \"2009-31-10\" using configuration from",
"@org.springframework.format.annotation.DateTimeFormat", "iso=DATE")
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
.hasMessageStartingWith("Text '2009-31-10'")
.hasCauseInstanceOf(DateTimeException.class).getCause()
.hasMessageContaining("Invalid value for MonthOfYear (valid values 1 - 12): 31")
.hasNoCause();
}
@Test
void testBindISOTime() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
@@ -550,12 +519,9 @@ class DateTimeFormattingTests {
.hasMessageContainingAll(
"Unable to parse date time value \"210302\" using configuration from",
"@org.springframework.format.annotation.DateTimeFormat",
"yyyy-MM-dd", "M/d/yy", "yyyyMMdd", "yyyy.MM.dd")
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
.hasMessageStartingWith("Text '210302'")
.hasNoCause();
"yyyy-MM-dd", "M/d/yy", "yyyyMMdd", "yyyy.MM.dd");
}
}
}
public static class DateTimeBean {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -1261,31 +1261,6 @@ class CronExpressionTests {
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
}
@Test
public void daylightSaving() {
CronExpression cronExpression = CronExpression.parse("0 0 9 * * *");
ZonedDateTime last = ZonedDateTime.parse("2021-03-27T09:00:00+01:00[Europe/Amsterdam]");
ZonedDateTime expected = ZonedDateTime.parse("2021-03-28T09:00:00+02:00[Europe/Amsterdam]");
ZonedDateTime actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
last = ZonedDateTime.parse("2021-10-30T09:00:00+02:00[Europe/Amsterdam]");
expected = ZonedDateTime.parse("2021-10-31T09:00:00+01:00[Europe/Amsterdam]");
actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
cronExpression = CronExpression.parse("0 10 2 * * *");
last = ZonedDateTime.parse("2013-03-31T01:09:00+01:00[Europe/Amsterdam]");
expected = ZonedDateTime.parse("2013-04-01T02:10:00+02:00[Europe/Amsterdam]");
actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -57,7 +57,7 @@ class CronTriggerTests {
@ParameterizedCronTriggerTest
void matchAll(LocalDateTime localDateTime, TimeZone timeZone) {
void testMatchAll(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("* * * * * *", timeZone);
@@ -66,7 +66,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void matchLastSecond(LocalDateTime localDateTime, TimeZone timeZone) {
void testMatchLastSecond(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("* * * * * *", timeZone);
@@ -76,7 +76,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void matchSpecificSecond(LocalDateTime localDateTime, TimeZone timeZone) {
void testMatchSpecificSecond(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("10 * * * * *", timeZone);
@@ -86,7 +86,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementSecondByOne(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementSecondByOne(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("11 * * * * *", timeZone);
@@ -98,7 +98,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementSecondWithPreviousExecutionTooEarly(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementSecondWithPreviousExecutionTooEarly(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("11 * * * * *", timeZone);
@@ -111,7 +111,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementSecondAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementSecondAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("10 * * * * *", timeZone);
@@ -123,7 +123,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void secondRange(LocalDateTime localDateTime, TimeZone timeZone) {
void testSecondRange(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("10-15 * * * * *", timeZone);
@@ -134,7 +134,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementMinute(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementMinute(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 * * * * *", timeZone);
@@ -152,7 +152,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementMinuteByOne(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementMinuteByOne(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 11 * * * *", timeZone);
@@ -164,7 +164,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementMinuteAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementMinuteAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 10 * * * *", timeZone);
@@ -177,7 +177,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementHour(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementHour(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 * * * *", timeZone);
@@ -198,7 +198,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementHourAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementHourAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 * * * *", timeZone);
@@ -220,7 +220,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementDayOfMonth(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementDayOfMonth(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 0 * * *", timeZone);
@@ -236,13 +236,13 @@ class CronTriggerTests {
assertThat(this.calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(2);
this.calendar.add(Calendar.DAY_OF_MONTH, 1);
TriggerContext context2 = getTriggerContext(localDate);
Object actual = trigger.nextExecutionTime(context2);
Object actual = localDate = trigger.nextExecutionTime(context2);
assertThat(actual).isEqualTo(this.calendar.getTime());
assertThat(this.calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(3);
}
@ParameterizedCronTriggerTest
void incrementDayOfMonthByOne(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementDayOfMonthByOne(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("* * * 10 * *", timeZone);
@@ -257,7 +257,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementDayOfMonthAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementDayOfMonthAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("* * * 10 * *", timeZone);
@@ -273,7 +273,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void dailyTriggerInShortMonth(LocalDateTime localDateTime, TimeZone timeZone) {
void testDailyTriggerInShortMonth(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 0 * * *", timeZone);
@@ -294,7 +294,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void dailyTriggerInLongMonth(LocalDateTime localDateTime, TimeZone timeZone) {
void testDailyTriggerInLongMonth(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 0 * * *", timeZone);
@@ -315,7 +315,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void dailyTriggerOnDaylightSavingBoundary(LocalDateTime localDateTime, TimeZone timeZone) {
void testDailyTriggerOnDaylightSavingBoundary(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 0 * * *", timeZone);
@@ -336,7 +336,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementMonth(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementMonth(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 0 1 * *", timeZone);
@@ -357,7 +357,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementMonthAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementMonthAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 0 1 * *", timeZone);
@@ -380,7 +380,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void monthlyTriggerInLongMonth(LocalDateTime localDateTime, TimeZone timeZone) {
void testMonthlyTriggerInLongMonth(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 0 31 * *", timeZone);
@@ -396,7 +396,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void monthlyTriggerInShortMonth(LocalDateTime localDateTime, TimeZone timeZone) {
void testMonthlyTriggerInShortMonth(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 0 1 * *", timeZone);
@@ -413,7 +413,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementDayOfWeekByOne(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementDayOfWeekByOne(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("* * * * * 2", timeZone);
@@ -429,7 +429,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void incrementDayOfWeekAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
void testIncrementDayOfWeekAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("* * * * * 2", timeZone);
@@ -445,7 +445,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void specificMinuteSecond(LocalDateTime localDateTime, TimeZone timeZone) {
void testSpecificMinuteSecond(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("55 5 * * * *", timeZone);
@@ -459,12 +459,12 @@ class CronTriggerTests {
assertThat(actual1).isEqualTo(this.calendar.getTime());
this.calendar.add(Calendar.HOUR, 1);
TriggerContext context2 = getTriggerContext(localDate);
Object actual = trigger.nextExecutionTime(context2);
Object actual = localDate = trigger.nextExecutionTime(context2);
assertThat(actual).isEqualTo(this.calendar.getTime());
}
@ParameterizedCronTriggerTest
void specificHourSecond(LocalDateTime localDateTime, TimeZone timeZone) {
void testSpecificHourSecond(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("55 * 10 * * *", timeZone);
@@ -479,12 +479,12 @@ class CronTriggerTests {
assertThat(actual1).isEqualTo(this.calendar.getTime());
this.calendar.add(Calendar.MINUTE, 1);
TriggerContext context2 = getTriggerContext(localDate);
Object actual = trigger.nextExecutionTime(context2);
Object actual = localDate = trigger.nextExecutionTime(context2);
assertThat(actual).isEqualTo(this.calendar.getTime());
}
@ParameterizedCronTriggerTest
void specificMinuteHour(LocalDateTime localDateTime, TimeZone timeZone) {
void testSpecificMinuteHour(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("* 5 10 * * *", timeZone);
@@ -500,12 +500,12 @@ class CronTriggerTests {
// next trigger is in one second because second is wildcard
this.calendar.add(Calendar.SECOND, 1);
TriggerContext context2 = getTriggerContext(localDate);
Object actual = trigger.nextExecutionTime(context2);
Object actual = localDate = trigger.nextExecutionTime(context2);
assertThat(actual).isEqualTo(this.calendar.getTime());
}
@ParameterizedCronTriggerTest
void specificDayOfMonthSecond(LocalDateTime localDateTime, TimeZone timeZone) {
void testSpecificDayOfMonthSecond(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("55 * * 3 * *", timeZone);
@@ -521,12 +521,12 @@ class CronTriggerTests {
assertThat(actual1).isEqualTo(this.calendar.getTime());
this.calendar.add(Calendar.MINUTE, 1);
TriggerContext context2 = getTriggerContext(localDate);
Object actual = trigger.nextExecutionTime(context2);
Object actual = localDate = trigger.nextExecutionTime(context2);
assertThat(actual).isEqualTo(this.calendar.getTime());
}
@ParameterizedCronTriggerTest
void specificDate(LocalDateTime localDateTime, TimeZone timeZone) {
void testSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("* * * 3 11 *", timeZone);
@@ -543,12 +543,12 @@ class CronTriggerTests {
assertThat(actual1).isEqualTo(this.calendar.getTime());
this.calendar.add(Calendar.SECOND, 1);
TriggerContext context2 = getTriggerContext(localDate);
Object actual = trigger.nextExecutionTime(context2);
Object actual = localDate = trigger.nextExecutionTime(context2);
assertThat(actual).isEqualTo(this.calendar.getTime());
}
@ParameterizedCronTriggerTest
void nonExistentSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
void testNonExistentSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
// TODO: maybe try and detect this as a special case in parser?
@@ -561,7 +561,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void leapYearSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
void testLeapYearSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 0 29 2 *", timeZone);
@@ -579,12 +579,12 @@ class CronTriggerTests {
assertThat(actual1).isEqualTo(this.calendar.getTime());
this.calendar.add(Calendar.YEAR, 4);
TriggerContext context2 = getTriggerContext(localDate);
Object actual = trigger.nextExecutionTime(context2);
Object actual = localDate = trigger.nextExecutionTime(context2);
assertThat(actual).isEqualTo(this.calendar.getTime());
}
@ParameterizedCronTriggerTest
void weekDaySequence(LocalDateTime localDateTime, TimeZone timeZone) {
void testWeekDaySequence(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 0 7 ? * MON-FRI", timeZone);
@@ -607,12 +607,12 @@ class CronTriggerTests {
assertThat(actual1).isEqualTo(this.calendar.getTime());
this.calendar.add(Calendar.DAY_OF_MONTH, 1);
TriggerContext context3 = getTriggerContext(localDate);
Object actual = trigger.nextExecutionTime(context3);
Object actual = localDate = trigger.nextExecutionTime(context3);
assertThat(actual).isEqualTo(this.calendar.getTime());
}
@ParameterizedCronTriggerTest
void dayOfWeekIndifferent(LocalDateTime localDateTime, TimeZone timeZone) {
void testDayOfWeekIndifferent(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("* * * 2 * *", timeZone);
@@ -621,7 +621,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void secondIncrementer(LocalDateTime localDateTime, TimeZone timeZone) {
void testSecondIncrementer(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("57,59 * * * * *", timeZone);
@@ -630,7 +630,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void secondIncrementerWithRange(LocalDateTime localDateTime, TimeZone timeZone) {
void testSecondIncrementerWithRange(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("1,3,5 * * * * *", timeZone);
@@ -639,7 +639,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void hourIncrementer(LocalDateTime localDateTime, TimeZone timeZone) {
void testHourIncrementer(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("* * 4,8,12,16,20 * * *", timeZone);
@@ -648,7 +648,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void dayNames(LocalDateTime localDateTime, TimeZone timeZone) {
void testDayNames(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("* * * * * 0-6", timeZone);
@@ -657,7 +657,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void sundayIsZero(LocalDateTime localDateTime, TimeZone timeZone) {
void testSundayIsZero(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("* * * * * 0", timeZone);
@@ -666,7 +666,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void sundaySynonym(LocalDateTime localDateTime, TimeZone timeZone) {
void testSundaySynonym(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("* * * * * 0", timeZone);
@@ -675,7 +675,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void monthNames(LocalDateTime localDateTime, TimeZone timeZone) {
void testMonthNames(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("* * * * 1-12 *", timeZone);
@@ -684,7 +684,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void monthNamesMixedCase(LocalDateTime localDateTime, TimeZone timeZone) {
void testMonthNamesMixedCase(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("* * * * 2 *", timeZone);
@@ -693,91 +693,91 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void secondInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testSecondInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("77 * * * * *", timeZone));
}
@ParameterizedCronTriggerTest
void secondRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testSecondRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("44-77 * * * * *", timeZone));
}
@ParameterizedCronTriggerTest
void minuteInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testMinuteInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* 77 * * * *", timeZone));
}
@ParameterizedCronTriggerTest
void minuteRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testMinuteRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* 44-77 * * * *", timeZone));
}
@ParameterizedCronTriggerTest
void hourInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testHourInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * 27 * * *", timeZone));
}
@ParameterizedCronTriggerTest
void hourRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testHourRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * 23-28 * * *", timeZone));
}
@ParameterizedCronTriggerTest
void dayInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testDayInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * * 45 * *", timeZone));
}
@ParameterizedCronTriggerTest
void dayRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testDayRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * * 28-45 * *", timeZone));
}
@ParameterizedCronTriggerTest
void monthInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testMonthInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("0 0 0 25 13 ?", timeZone));
}
@ParameterizedCronTriggerTest
void monthInvalidTooSmall(LocalDateTime localDateTime, TimeZone timeZone) {
void testMonthInvalidTooSmall(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("0 0 0 25 0 ?", timeZone));
}
@ParameterizedCronTriggerTest
void dayOfMonthInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testDayOfMonthInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("0 0 0 32 12 ?", timeZone));
}
@ParameterizedCronTriggerTest
void monthRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
void testMonthRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * * * 11-13 *", timeZone));
}
@ParameterizedCronTriggerTest
void whitespace(LocalDateTime localDateTime, TimeZone timeZone) {
void testWhitespace(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger1 = new CronTrigger("* * * * 1 *", timeZone);
@@ -786,7 +786,7 @@ class CronTriggerTests {
}
@ParameterizedCronTriggerTest
void monthSequence(LocalDateTime localDateTime, TimeZone timeZone) {
void testMonthSequence(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
CronTrigger trigger = new CronTrigger("0 30 23 30 1/3 ?", timeZone);
@@ -808,33 +808,23 @@ class CronTriggerTests {
// Next trigger is 3 months latter
this.calendar.add(Calendar.MONTH, 3);
TriggerContext context3 = getTriggerContext(localDate);
Object actual = trigger.nextExecutionTime(context3);
Object actual = localDate = trigger.nextExecutionTime(context3);
assertThat(actual).isEqualTo(this.calendar.getTime());
}
@ParameterizedCronTriggerTest
void daylightSavingMissingHour(LocalDateTime localDateTime, TimeZone timeZone) {
void testDaylightSavingMissingHour(LocalDateTime localDateTime, TimeZone timeZone) {
setUp(localDateTime, timeZone);
// This trigger has to be somewhere between 2:00 AM and 3:00 AM, so we
// use a cron expression for 2:10 AM every day.
// This trigger has to be somewhere in between 2am and 3am
CronTrigger trigger = new CronTrigger("0 10 2 * * *", timeZone);
// 2:00 AM on March 31, 2013: start of Daylight Saving Time for CET in 2013.
// Setting up last completion:
// - PST: Sun Mar 31 10:09:54 CEST 2013
// - CET: Sun Mar 31 01:09:54 CET 2013
this.calendar.set(Calendar.DAY_OF_MONTH, 31);
this.calendar.set(Calendar.MONTH, Calendar.MARCH);
this.calendar.set(Calendar.YEAR, 2013);
this.calendar.set(Calendar.HOUR_OF_DAY, 1);
this.calendar.set(Calendar.MINUTE, 9);
this.calendar.set(Calendar.SECOND, 54);
Date lastCompletionTime = this.calendar.getTime();
// Setting up expected next execution time:
// - PST: Sun Mar 31 11:10:00 CEST 2013
// - CET: Mon Apr 01 02:10:00 CEST 2013
Date localDate = this.calendar.getTime();
TriggerContext context1 = getTriggerContext(localDate);
if (timeZone.equals(TimeZone.getTimeZone("CET"))) {
// Clocks go forward an hour so 2am doesn't exist in CET for this localDateTime
this.calendar.add(Calendar.DAY_OF_MONTH, 1);
@@ -842,10 +832,8 @@ class CronTriggerTests {
this.calendar.add(Calendar.HOUR_OF_DAY, 1);
this.calendar.set(Calendar.MINUTE, 10);
this.calendar.set(Calendar.SECOND, 0);
TriggerContext context = getTriggerContext(lastCompletionTime);
Object nextExecutionTime = trigger.nextExecutionTime(context);
assertThat(nextExecutionTime).isEqualTo(this.calendar.getTime());
Object actual = localDate = trigger.nextExecutionTime(context1);
assertThat(actual).isEqualTo(this.calendar.getTime());
}
private static void roundup(Calendar calendar) {
+3 -3
View File
@@ -8,7 +8,7 @@ apply plugin: "kotlin"
// cglib itself depends on asm and is therefore further transformed by the ShadowJar task to
// depend on org.springframework.asm; this avoids including two different copies of asm.
def cglibVersion = "3.3.0"
def objenesisVersion = "3.2"
def objenesisVersion = "3.1"
configurations {
cglib
@@ -70,8 +70,8 @@ dependencies {
jar {
reproducibleFileOrder = true
preserveFileTimestamps = false // maybe not necessary here, but good for reproducibility
manifest.attributes["Dependencies"] = "jdk.unsupported" // for WildFly (-> Objenesis 3.2)
preserveFileTimestamps = false // maybe not necessary here, but good for reproducibility
manifest.attributes["Dependencies"] = "jdk.unsupported" // JBoss modules
// Inline repackaged cglib classes directly into spring-core jar
dependsOn cglibRepackJar
@@ -163,7 +163,7 @@ public final class BridgeMethodResolver {
}
}
// A non-array type: compare the type itself.
if (!ClassUtils.resolvePrimitiveIfNecessary(candidateParameter).equals(ClassUtils.resolvePrimitiveIfNecessary(genericParameter.toClass()))) {
if (!candidateParameter.equals(genericParameter.toClass())) {
return false;
}
}
@@ -1,6 +1,6 @@
/**
* Spring's repackaging of
* <a href="http://objenesis.org">Objenesis 3.2</a>
* <a href="http://objenesis.org">Objenesis 3.0</a>
* (with SpringObjenesis entry point; for internal use only).
*
* <p>This repackaging technique avoids any potential conflicts with
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -299,7 +299,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
@Override
@Nullable
public V remove(@Nullable Object key) {
public V remove(Object key) {
return doTask(key, new Task<V>(TaskOption.RESTRUCTURE_AFTER, TaskOption.SKIP_IF_EMPTY) {
@Override
@Nullable
@@ -316,7 +316,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
}
@Override
public boolean remove(@Nullable Object key, final @Nullable Object value) {
public boolean remove(Object key, final Object value) {
Boolean result = doTask(key, new Task<Boolean>(TaskOption.RESTRUCTURE_AFTER, TaskOption.SKIP_IF_EMPTY) {
@Override
protected Boolean execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry) {
@@ -333,7 +333,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
}
@Override
public boolean replace(@Nullable K key, final @Nullable V oldValue, final @Nullable V newValue) {
public boolean replace(K key, final V oldValue, final V newValue) {
Boolean result = doTask(key, new Task<Boolean>(TaskOption.RESTRUCTURE_BEFORE, TaskOption.SKIP_IF_EMPTY) {
@Override
protected Boolean execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry) {
@@ -349,7 +349,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
@Override
@Nullable
public V replace(@Nullable K key, final @Nullable V value) {
public V replace(K key, final V value) {
return doTask(key, new Task<V>(TaskOption.RESTRUCTURE_BEFORE, TaskOption.SKIP_IF_EMPTY) {
@Override
@Nullable
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -211,13 +211,7 @@ public class LinkedCaseInsensitiveMap<V> implements Map<String, V>, Serializable
public V putIfAbsent(String key, @Nullable V value) {
String oldKey = this.caseInsensitiveKeys.putIfAbsent(convertKey(key), key);
if (oldKey != null) {
V oldKeyValue = this.targetMap.get(oldKey);
if (oldKeyValue != null) {
return oldKeyValue;
}
else {
key = oldKey;
}
return this.targetMap.get(oldKey);
}
return this.targetMap.putIfAbsent(key, value);
}
@@ -227,13 +221,7 @@ public class LinkedCaseInsensitiveMap<V> implements Map<String, V>, Serializable
public V computeIfAbsent(String key, Function<? super String, ? extends V> mappingFunction) {
String oldKey = this.caseInsensitiveKeys.putIfAbsent(convertKey(key), key);
if (oldKey != null) {
V oldKeyValue = this.targetMap.get(oldKey);
if (oldKeyValue != null) {
return oldKeyValue;
}
else {
key = oldKey;
}
return this.targetMap.get(oldKey);
}
return this.targetMap.computeIfAbsent(key, mappingFunction);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -68,7 +68,7 @@ public abstract class PatternMatchUtils {
}
return (str.length() >= firstIndex &&
pattern.startsWith(str.substring(0, firstIndex)) &&
pattern.substring(0, firstIndex).equals(str.substring(0, firstIndex)) &&
simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex)));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -28,11 +28,9 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
/**
* Utility class for working with Strings that have placeholder values in them.
* A placeholder takes the form {@code ${name}}. Using {@code PropertyPlaceholderHelper}
* these placeholders can be substituted for user-supplied values.
*
* <p>Values for substitution can be supplied using a {@link Properties} instance or
* Utility class for working with Strings that have placeholder values in them. A placeholder takes the form
* {@code ${name}}. Using {@code PropertyPlaceholderHelper} these placeholders can be substituted for
* user-supplied values. <p> Values for substitution can be supplied using a {@link Properties} instance or
* using a {@link PlaceholderResolver}.
*
* @author Juergen Hoeller
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -292,7 +292,7 @@ class StaxEventXMLReader extends AbstractStaxXMLReader {
private void handleDtd(DTD dtd) throws SAXException {
if (getLexicalHandler() != null) {
Location location = dtd.getLocation();
javax.xml.stream.Location location = dtd.getLocation();
getLexicalHandler().startDTD(null, location.getPublicId(), location.getSystemId());
}
if (getLexicalHandler() != null) {
@@ -34,7 +34,7 @@ operator fun PropertyResolver.get(key: String) : String? = getProperty(key)
/**
* Extension for [PropertyResolver.getProperty] providing a `getProperty<Foo>(...)`
* variant returning a nullable `Foo`.
* variant returning a nullable [String].
*
* @author Sebastien Deleuze
* @since 5.1
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -99,12 +99,6 @@ class LinkedCaseInsensitiveMapTests {
assertThat(map.computeIfAbsent("key", key2 -> "value1")).isEqualTo("value3");
assertThat(map.computeIfAbsent("KEY", key1 -> "value2")).isEqualTo("value3");
assertThat(map.computeIfAbsent("Key", key -> "value3")).isEqualTo("value3");
assertThat(map.put("null", null)).isNull();
assertThat(map.putIfAbsent("NULL", "value")).isNull();
assertThat(map.put("null", null)).isEqualTo("value");
assertThat(map.computeIfAbsent("NULL", s -> "value")).isEqualTo("value");
assertThat(map.get("null")).isEqualTo("value");
}
@Test
@@ -1,71 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
class KotlinBridgeMethodResolverTests {
@Test
fun findBridgedMethod() {
val unbridged = GenericRepository::class.java.getDeclaredMethod("delete", Int::class.java)
val bridged = GenericRepository::class.java.getDeclaredMethod("delete", Any::class.java)
Assertions.assertThat(unbridged.isBridge).isFalse
Assertions.assertThat(bridged.isBridge).isTrue
Assertions.assertThat(BridgeMethodResolver.findBridgedMethod(unbridged)).`as`("Unbridged method not returned directly").isEqualTo(unbridged)
Assertions.assertThat(BridgeMethodResolver.findBridgedMethod(bridged)).`as`("Incorrect bridged method returned").isEqualTo(unbridged)
}
@Test
fun findBridgedMethodWithArrays() {
val unbridged = GenericRepository::class.java.getDeclaredMethod("delete", Array<Int>::class.java)
val bridged = GenericRepository::class.java.getDeclaredMethod("delete", Array<Any>::class.java)
Assertions.assertThat(unbridged.isBridge).isFalse
Assertions.assertThat(bridged.isBridge).isTrue
Assertions.assertThat(BridgeMethodResolver.findBridgedMethod(unbridged)).`as`("Unbridged method not returned directly").isEqualTo(unbridged)
Assertions.assertThat(BridgeMethodResolver.findBridgedMethod(bridged)).`as`("Incorrect bridged method returned").isEqualTo(unbridged)
}
}
interface GenericInterface<ID> {
fun delete(id: ID)
fun delete(ids: Array<ID>)
}
abstract class AbstractGenericClass<ID> : GenericInterface<ID> {
override fun delete(id: ID) {
}
override fun delete(ids: Array<ID>) {
}
}
class GenericRepository : AbstractGenericClass<Int>() {
override fun delete(id: Int) {
error("gotcha")
}
override fun delete(ids: Array<Int>) {
error("gotcha")
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,6 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
@@ -90,12 +89,8 @@ public abstract class AbstractDataBufferAllocatingTests {
}
protected Consumer<DataBuffer> stringConsumer(String expected) {
return stringConsumer(expected, UTF_8);
}
protected Consumer<DataBuffer> stringConsumer(String expected, Charset charset) {
return dataBuffer -> {
String value = dataBuffer.toString(charset);
String value = dataBuffer.toString(UTF_8);
DataBufferUtils.release(dataBuffer);
assertThat(value).isEqualTo(expected);
};
@@ -136,7 +136,6 @@ public final class SpelCompiler implements Opcodes {
private Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl expressionToCompile) {
// Create class outline 'spel/ExNNN extends org.springframework.expression.spel.CompiledExpression'
String className = "spel/Ex" + getNextSuffix();
String evaluationContextClass = "org/springframework/expression/EvaluationContext";
ClassWriter cw = new ExpressionClassWriter();
cw.visit(V1_8, ACC_PUBLIC, className, null, "org/springframework/expression/spel/CompiledExpression", null);
@@ -152,7 +151,7 @@ public final class SpelCompiler implements Opcodes {
// Create getValue() method
mv = cw.visitMethod(ACC_PUBLIC, "getValue",
"(Ljava/lang/Object;L" + evaluationContextClass + ";)Ljava/lang/Object;", null,
"(Ljava/lang/Object;Lorg/springframework/expression/EvaluationContext;)Ljava/lang/Object;", null,
new String[] {"org/springframework/expression/EvaluationException"});
mv.visitCode();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -49,7 +49,7 @@ public abstract class AbstractExpressionTests {
/**
* Evaluate an expression and check that the actual result matches the
* expectedValue and the class of the result matches the expectedResultType.
* expectedValue and the class of the result matches the expectedClassOfResult.
* @param expression the expression to evaluate
* @param expectedValue the expected result for evaluating the expression
* @param expectedResultType the expected class of the evaluation result
@@ -106,15 +106,15 @@ public abstract class AbstractExpressionTests {
/**
* Evaluate an expression and check that the actual result matches the
* expectedValue and the class of the result matches the expectedResultType.
* expectedValue and the class of the result matches the expectedClassOfResult.
* This method can also check if the expression is writable (for example,
* it is a variable or property reference).
* @param expression the expression to evaluate
* @param expectedValue the expected result for evaluating the expression
* @param expectedResultType the expected class of the evaluation result
* @param expectedClassOfResult the expected class of the evaluation result
* @param shouldBeWritable should the parsed expression be writable?
*/
public void evaluate(String expression, Object expectedValue, Class<?> expectedResultType, boolean shouldBeWritable) {
public void evaluate(String expression, Object expectedValue, Class<?> expectedClassOfResult, boolean shouldBeWritable) {
Expression expr = parser.parseExpression(expression);
assertThat(expr).as("expression").isNotNull();
if (DEBUG) {
@@ -134,7 +134,7 @@ public abstract class AbstractExpressionTests {
else {
assertThat(value).as("Did not get expected value for expression '" + expression + "'.").isEqualTo(expectedValue);
}
assertThat(expectedResultType.equals(resultType)).as("Type of the result was not as expected. Expected '" + expectedResultType +
assertThat(expectedClassOfResult.equals(resultType)).as("Type of the result was not as expected. Expected '" + expectedClassOfResult +
"' but result was of type '" + resultType + "'").isTrue();
assertThat(expr.isWritable(context)).as("isWritable").isEqualTo(shouldBeWritable);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,6 +17,7 @@
package org.springframework.expression.spel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -39,79 +40,98 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Sam Brannen
* @author Juergen Hoeller
*/
class SelectionAndProjectionTests {
public class SelectionAndProjectionTests {
@Test
@SuppressWarnings("unchecked")
void selectionWithList() throws Exception {
public void selectionWithList() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ListTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(List.class);
List<Integer> list = (List<Integer>) value;
assertThat(list).containsExactly(0, 1, 2, 3, 4);
boolean condition = value instanceof List;
assertThat(condition).isTrue();
List<?> list = (List<?>) value;
assertThat(list.size()).isEqualTo(5);
assertThat(list.get(0)).isEqualTo(0);
assertThat(list.get(1)).isEqualTo(1);
assertThat(list.get(2)).isEqualTo(2);
assertThat(list.get(3)).isEqualTo(3);
assertThat(list.get(4)).isEqualTo(4);
}
@Test
void selectFirstItemInList() throws Exception {
public void selectFirstItemInList() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.^[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ListTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(Integer.class);
boolean condition = value instanceof Integer;
assertThat(condition).isTrue();
assertThat(value).isEqualTo(0);
}
@Test
void selectLastItemInList() throws Exception {
public void selectLastItemInList() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.$[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ListTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(Integer.class);
boolean condition = value instanceof Integer;
assertThat(condition).isTrue();
assertThat(value).isEqualTo(4);
}
@Test
@SuppressWarnings("unchecked")
void selectionWithSet() throws Exception {
public void selectionWithSet() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new SetTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(List.class);
List<Integer> list = (List<Integer>) value;
assertThat(list).containsExactly(0, 1, 2, 3, 4);
boolean condition = value instanceof List;
assertThat(condition).isTrue();
List<?> list = (List<?>) value;
assertThat(list.size()).isEqualTo(5);
assertThat(list.get(0)).isEqualTo(0);
assertThat(list.get(1)).isEqualTo(1);
assertThat(list.get(2)).isEqualTo(2);
assertThat(list.get(3)).isEqualTo(3);
assertThat(list.get(4)).isEqualTo(4);
}
@Test
void selectFirstItemInSet() throws Exception {
public void selectFirstItemInSet() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.^[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new SetTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(Integer.class);
boolean condition = value instanceof Integer;
assertThat(condition).isTrue();
assertThat(value).isEqualTo(0);
}
@Test
void selectLastItemInSet() throws Exception {
public void selectLastItemInSet() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.$[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new SetTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(Integer.class);
boolean condition = value instanceof Integer;
assertThat(condition).isTrue();
assertThat(value).isEqualTo(4);
}
@Test
@SuppressWarnings("unchecked")
void selectionWithIterable() throws Exception {
public void selectionWithIterable() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new IterableTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(List.class);
List<Integer> list = (List<Integer>) value;
assertThat(list).containsExactly(0, 1, 2, 3, 4);
boolean condition = value instanceof List;
assertThat(condition).isTrue();
List<?> list = (List<?>) value;
assertThat(list.size()).isEqualTo(5);
assertThat(list.get(0)).isEqualTo(0);
assertThat(list.get(1)).isEqualTo(1);
assertThat(list.get(2)).isEqualTo(2);
assertThat(list.get(3)).isEqualTo(3);
assertThat(list.get(4)).isEqualTo(4);
}
@Test
void selectionWithArray() throws Exception {
public void selectionWithArray() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
@@ -119,29 +139,36 @@ class SelectionAndProjectionTests {
TypedValue typedValue = new TypedValue(value);
assertThat(typedValue.getTypeDescriptor().getElementTypeDescriptor().getType()).isEqualTo(Integer.class);
Integer[] array = (Integer[]) value;
assertThat(array).containsExactly(0, 1, 2, 3, 4);
assertThat(array.length).isEqualTo(5);
assertThat(array[0]).isEqualTo(0);
assertThat(array[1]).isEqualTo(1);
assertThat(array[2]).isEqualTo(2);
assertThat(array[3]).isEqualTo(3);
assertThat(array[4]).isEqualTo(4);
}
@Test
void selectFirstItemInArray() throws Exception {
public void selectFirstItemInArray() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.^[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(Integer.class);
boolean condition = value instanceof Integer;
assertThat(condition).isTrue();
assertThat(value).isEqualTo(0);
}
@Test
void selectLastItemInArray() throws Exception {
public void selectLastItemInArray() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("integers.$[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(Integer.class);
boolean condition = value instanceof Integer;
assertThat(condition).isTrue();
assertThat(value).isEqualTo(4);
}
@Test
void selectionWithPrimitiveArray() throws Exception {
public void selectionWithPrimitiveArray() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("ints.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
@@ -149,41 +176,51 @@ class SelectionAndProjectionTests {
TypedValue typedValue = new TypedValue(value);
assertThat(typedValue.getTypeDescriptor().getElementTypeDescriptor().getType()).isEqualTo(Integer.class);
Integer[] array = (Integer[]) value;
assertThat(array).containsExactly(0, 1, 2, 3, 4);
assertThat(array.length).isEqualTo(5);
assertThat(array[0]).isEqualTo(0);
assertThat(array[1]).isEqualTo(1);
assertThat(array[2]).isEqualTo(2);
assertThat(array[3]).isEqualTo(3);
assertThat(array[4]).isEqualTo(4);
}
@Test
void selectFirstItemInPrimitiveArray() throws Exception {
public void selectFirstItemInPrimitiveArray() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("ints.^[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(Integer.class);
boolean condition = value instanceof Integer;
assertThat(condition).isTrue();
assertThat(value).isEqualTo(0);
}
@Test
void selectLastItemInPrimitiveArray() throws Exception {
public void selectLastItemInPrimitiveArray() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("ints.$[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(Integer.class);
boolean condition = value instanceof Integer;
assertThat(condition).isTrue();
assertThat(value).isEqualTo(4);
}
@Test
@SuppressWarnings("unchecked")
void selectionWithMap() {
public void selectionWithMap() {
EvaluationContext context = new StandardEvaluationContext(new MapTestBean());
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("colors.?[key.startsWith('b')]");
Map<String, String> colorsMap = (Map<String, String>) exp.getValue(context);
assertThat(colorsMap).containsOnlyKeys("beige", "blue", "brown");
assertThat(colorsMap.size()).isEqualTo(3);
assertThat(colorsMap.containsKey("beige")).isTrue();
assertThat(colorsMap.containsKey("blue")).isTrue();
assertThat(colorsMap.containsKey("brown")).isTrue();
}
@Test
@SuppressWarnings("unchecked")
void selectFirstItemInMap() {
public void selectFirstItemInMap() {
EvaluationContext context = new StandardEvaluationContext(new MapTestBean());
ExpressionParser parser = new SpelExpressionParser();
@@ -195,7 +232,7 @@ class SelectionAndProjectionTests {
@Test
@SuppressWarnings("unchecked")
void selectLastItemInMap() {
public void selectLastItemInMap() {
EvaluationContext context = new StandardEvaluationContext(new MapTestBean());
ExpressionParser parser = new SpelExpressionParser();
@@ -206,43 +243,52 @@ class SelectionAndProjectionTests {
}
@Test
@SuppressWarnings("unchecked")
void projectionWithList() throws Exception {
public void projectionWithList() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("#testList.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testList", IntegerTestBean.createList());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(List.class);
List<Integer> list = (List<Integer>) value;
assertThat(list).containsExactly(5, 6, 7);
boolean condition = value instanceof List;
assertThat(condition).isTrue();
List<?> list = (List<?>) value;
assertThat(list.size()).isEqualTo(3);
assertThat(list.get(0)).isEqualTo(5);
assertThat(list.get(1)).isEqualTo(6);
assertThat(list.get(2)).isEqualTo(7);
}
@Test
@SuppressWarnings("unchecked")
void projectionWithSet() throws Exception {
public void projectionWithSet() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("#testList.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testList", IntegerTestBean.createSet());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(List.class);
List<Integer> list = (List<Integer>) value;
assertThat(list).containsExactly(5, 6, 7);
boolean condition = value instanceof List;
assertThat(condition).isTrue();
List<?> list = (List<?>) value;
assertThat(list.size()).isEqualTo(3);
assertThat(list.get(0)).isEqualTo(5);
assertThat(list.get(1)).isEqualTo(6);
assertThat(list.get(2)).isEqualTo(7);
}
@Test
@SuppressWarnings("unchecked")
void projectionWithIterable() throws Exception {
public void projectionWithIterable() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("#testList.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testList", IntegerTestBean.createIterable());
Object value = expression.getValue(context);
assertThat(value).isInstanceOf(List.class);
List<Integer> list = (List<Integer>) value;
assertThat(list).containsExactly(5, 6, 7);
boolean condition = value instanceof List;
assertThat(condition).isTrue();
List<?> list = (List<?>) value;
assertThat(list.size()).isEqualTo(3);
assertThat(list.get(0)).isEqualTo(5);
assertThat(list.get(1)).isEqualTo(6);
assertThat(list.get(2)).isEqualTo(7);
}
@Test
void projectionWithArray() throws Exception {
public void projectionWithArray() throws Exception {
Expression expression = new SpelExpressionParser().parseRaw("#testArray.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testArray", IntegerTestBean.createArray());
@@ -251,7 +297,10 @@ class SelectionAndProjectionTests {
TypedValue typedValue = new TypedValue(value);
assertThat(typedValue.getTypeDescriptor().getElementTypeDescriptor().getType()).isEqualTo(Number.class);
Number[] array = (Number[]) value;
assertThat(array).containsExactly(5, 5.9f, 7);
assertThat(array.length).isEqualTo(3);
assertThat(array[0]).isEqualTo(5);
assertThat(array[1]).isEqualTo(5.9f);
assertThat(array[2]).isEqualTo(7);
}
@@ -298,7 +347,12 @@ class SelectionAndProjectionTests {
}
public Iterable<Integer> getIntegers() {
return integers::iterator;
return new Iterable<Integer>() {
@Override
public Iterator<Integer> iterator() {
return integers.iterator();
}
};
}
}
@@ -375,7 +429,12 @@ class SelectionAndProjectionTests {
static Iterable<IntegerTestBean> createIterable() {
final Set<IntegerTestBean> set = createSet();
return set::iterator;
return new Iterable<IntegerTestBean>() {
@Override
public Iterator<IntegerTestBean> iterator() {
return set.iterator();
}
};
}
static IntegerTestBean[] createArray() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,12 +31,15 @@ import org.springframework.util.LinkedCaseInsensitiveMap;
* entry for each column, with the column name as key.
*
* <p>The Map implementation to use and the key to use for each column
* in the column Map can be customized by overriding {@link #createColumnMap}
* and {@link #getColumnKey}, respectively.
* in the column Map can be customized through overriding
* {@link #createColumnMap} and {@link #getColumnKey}, respectively.
*
* <p><b>Note:</b> By default, {@code ColumnMapRowMapper} will try to build a linked Map
* <p><b>Note:</b> By default, ColumnMapRowMapper will try to build a linked Map
* with case-insensitive keys, to preserve column order as well as allow any
* casing to be used for column names.
* casing to be used for column names. This requires Commons Collections on the
* classpath (which will be autodetected). Else, the fallback is a standard linked
* HashMap, which will still preserve column order but requires the application
* to specify the column names in the same casing as exposed by the driver.
*
* @author Juergen Hoeller
* @since 1.2
@@ -71,7 +74,6 @@ public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> {
/**
* Determine the key to use for the given column in the column Map.
* <p>By default, the supplied column name will be returned unmodified.
* @param columnName the column name as returned by the ResultSet
* @return the column key to use
* @see java.sql.ResultSetMetaData#getColumnName
@@ -84,9 +86,9 @@ public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> {
* Retrieve a JDBC object value for the specified column.
* <p>The default implementation uses the {@code getObject} method.
* Additionally, this implementation includes a "hack" to get around Oracle
* returning a non standard object for their TIMESTAMP data type.
* @param rs the ResultSet holding the data
* @param index the column index
* returning a non standard object for their TIMESTAMP datatype.
* @param rs is the ResultSet holding the data
* @param index is the column index
* @return the Object returned
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,9 +22,7 @@ import java.sql.SQLException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.TypeConverter;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -52,7 +50,7 @@ public class DataClassRowMapper<T> extends BeanPropertyRowMapper<T> {
private String[] constructorParameterNames;
@Nullable
private TypeDescriptor[] constructorParameterTypes;
private Class<?>[] constructorParameterTypes;
/**
@@ -77,13 +75,9 @@ public class DataClassRowMapper<T> extends BeanPropertyRowMapper<T> {
super.initialize(mappedClass);
this.mappedConstructor = BeanUtils.getResolvableConstructor(mappedClass);
int paramCount = this.mappedConstructor.getParameterCount();
if (paramCount > 0) {
if (this.mappedConstructor.getParameterCount() > 0) {
this.constructorParameterNames = BeanUtils.getParameterNames(this.mappedConstructor);
this.constructorParameterTypes = new TypeDescriptor[paramCount];
for (int i = 0; i < paramCount; i++) {
this.constructorParameterTypes[i] = new TypeDescriptor(new MethodParameter(this.mappedConstructor, i));
}
this.constructorParameterTypes = this.mappedConstructor.getParameterTypes();
}
}
@@ -96,9 +90,8 @@ public class DataClassRowMapper<T> extends BeanPropertyRowMapper<T> {
args = new Object[this.constructorParameterNames.length];
for (int i = 0; i < args.length; i++) {
String name = underscoreName(this.constructorParameterNames[i]);
TypeDescriptor td = this.constructorParameterTypes[i];
Object value = getColumnValue(rs, rs.findColumn(name), td.getType());
args[i] = tc.convertIfNecessary(value, td.getType(), td);
Class<?> type = this.constructorParameterTypes[i];
args[i] = tc.convertIfNecessary(getColumnValue(rs, rs.findColumn(name), type), type);
}
}
else {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,27 +40,22 @@ import org.springframework.jdbc.support.JdbcUtils;
*
* <p>Example:
*
* <pre class="code">
* create table tab (id int unsigned not null primary key, text varchar(100));
* <pre class="code">create table tab (id int unsigned not null primary key, text varchar(100));
* create table tab_sequence (value int not null);
* insert into tab_sequence values(0);</pre>
*
* <p>If {@code cacheSize} is set, the intermediate values are served without querying the
* If "cacheSize" is set, the intermediate values are served without querying the
* database. If the server or your application is stopped or crashes or a transaction
* is rolled back, the unused values will never be served. The maximum hole size in
* numbering is consequently the value of {@code cacheSize}.
* numbering is consequently the value of cacheSize.
*
* <p>It is possible to avoid acquiring a new connection for the incrementer by setting the
* "useNewConnection" property to false. In this case you <i>MUST</i> use a non-transactional
* storage engine like MYISAM when defining the incrementer table.
*
* <p>As of Spring Framework 5.3.7, {@code MySQLMaxValueIncrementer} is compatible with
* <a href="https://dev.mysql.com/doc/refman/8.0/en/mysql-tips.html#safe-updates">MySQL safe updates mode</a>.
*
* @author Jean-Pierre Pawlak
* @author Thomas Risberg
* @author Juergen Hoeller
* @author Sam Brannen
*/
public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer {
@@ -146,7 +141,7 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
String columnName = getColumnName();
try {
stmt.executeUpdate("update " + getIncrementerName() + " set " + columnName +
" = last_insert_id(" + columnName + " + " + getCacheSize() + ") limit 1");
" = last_insert_id(" + columnName + " + " + getCacheSize() + ")");
}
catch (SQLException ex) {
throw new DataAccessResourceFailureException("Could not increment " + columnName + " for " +
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -135,7 +135,6 @@ public abstract class AbstractRowMapperTests {
given(resultSet.getObject(anyInt(), any(Class.class))).willThrow(new SQLFeatureNotSupportedException());
given(resultSet.getDate(3)).willReturn(new java.sql.Date(1221222L));
given(resultSet.getBigDecimal(4)).willReturn(new BigDecimal("1234.56"));
given(resultSet.getObject(4)).willReturn(new BigDecimal("1234.56"));
given(resultSet.wasNull()).willReturn(type == MockType.TWO);
given(resultSetMetaData.getColumnCount()).willReturn(4);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,15 +16,11 @@
package org.springframework.jdbc.core;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.test.ConstructorPerson;
import org.springframework.jdbc.core.test.ConstructorPersonWithGenerics;
import static org.assertj.core.api.Assertions.assertThat;
@@ -46,20 +42,4 @@ public class DataClassRowMapperTests extends AbstractRowMapperTests {
mock.verifyClosed();
}
@Test
public void testStaticQueryWithDataClassAndGenerics() throws Exception {
Mock mock = new Mock();
List<ConstructorPersonWithGenerics> result = mock.getJdbcTemplate().query(
"select name, age, birth_date, balance from people",
new DataClassRowMapper<>(ConstructorPersonWithGenerics.class));
assertThat(result.size()).isEqualTo(1);
ConstructorPersonWithGenerics person = result.get(0);
assertThat(person.name()).isEqualTo("Bubba");
assertThat(person.age()).isEqualTo(22L);
assertThat(person.birth_date()).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L));
assertThat(person.balance()).isEqualTo(Collections.singletonList(new BigDecimal("1234.56")));
mock.verifyClosed();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,13 +24,13 @@ import java.util.Date;
*/
public class ConstructorPerson {
private final String name;
private String name;
private final long age;
private long age;
private final Date birth_date;
private java.util.Date birth_date;
private final BigDecimal balance;
private BigDecimal balance;
public ConstructorPerson(String name, long age, Date birth_date, BigDecimal balance) {
@@ -42,19 +42,19 @@ public class ConstructorPerson {
public String name() {
return this.name;
return name;
}
public long age() {
return this.age;
return age;
}
public Date birth_date() {
return this.birth_date;
return birth_date;
}
public BigDecimal balance() {
return this.balance;
return balance;
}
}
@@ -1,61 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jdbc.core.test;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* @author Juergen Hoeller
*/
public class ConstructorPersonWithGenerics {
private final String name;
private final long age;
private final Date birth_date;
private final List<BigDecimal> balance;
public ConstructorPersonWithGenerics(String name, long age, Date birth_date, List<BigDecimal> balance) {
this.name = name;
this.age = age;
this.birth_date = birth_date;
this.balance = balance;
}
public String name() {
return this.name;
}
public long age() {
return this.age;
}
public Date birth_date() {
return this.birth_date;
}
public List<BigDecimal> balance() {
return this.balance;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -25,7 +25,6 @@ import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
import org.springframework.jdbc.support.incrementer.HanaSequenceMaxValueIncrementer;
import org.springframework.jdbc.support.incrementer.HsqlMaxValueIncrementer;
import org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer;
@@ -39,13 +38,10 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Unit tests for {@link DataFieldMaxValueIncrementer} implementations.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 27.02.2004
*/
class DataFieldMaxValueIncrementerTests {
public class DataFieldMaxValueIncrementerTests {
private final DataSource dataSource = mock(DataSource.class);
@@ -57,7 +53,7 @@ class DataFieldMaxValueIncrementerTests {
@Test
void hanaSequenceMaxValueIncrementer() throws SQLException {
public void testHanaSequenceMaxValueIncrementer() throws SQLException {
given(dataSource.getConnection()).willReturn(connection);
given(connection.createStatement()).willReturn(statement);
given(statement.executeQuery("select myseq.nextval from dummy")).willReturn(resultSet);
@@ -79,7 +75,7 @@ class DataFieldMaxValueIncrementerTests {
}
@Test
void hsqlMaxValueIncrementer() throws SQLException {
public void testHsqlMaxValueIncrementer() throws SQLException {
given(dataSource.getConnection()).willReturn(connection);
given(connection.createStatement()).willReturn(statement);
given(statement.executeQuery("select max(identity()) from myseq")).willReturn(resultSet);
@@ -109,7 +105,7 @@ class DataFieldMaxValueIncrementerTests {
}
@Test
void hsqlMaxValueIncrementerWithDeleteSpecificValues() throws SQLException {
public void testHsqlMaxValueIncrementerWithDeleteSpecificValues() throws SQLException {
given(dataSource.getConnection()).willReturn(connection);
given(connection.createStatement()).willReturn(statement);
given(statement.executeQuery("select max(identity()) from myseq")).willReturn(resultSet);
@@ -140,7 +136,7 @@ class DataFieldMaxValueIncrementerTests {
}
@Test
void mySQLMaxValueIncrementer() throws SQLException {
public void testMySQLMaxValueIncrementer() throws SQLException {
given(dataSource.getConnection()).willReturn(connection);
given(connection.createStatement()).willReturn(statement);
given(statement.executeQuery("select last_insert_id()")).willReturn(resultSet);
@@ -160,14 +156,14 @@ class DataFieldMaxValueIncrementerTests {
assertThat(incrementer.nextStringValue()).isEqualTo("3");
assertThat(incrementer.nextLongValue()).isEqualTo(4);
verify(statement, times(2)).executeUpdate("update myseq set seq = last_insert_id(seq + 2) limit 1");
verify(statement, times(2)).executeUpdate("update myseq set seq = last_insert_id(seq + 2)");
verify(resultSet, times(2)).close();
verify(statement, times(2)).close();
verify(connection, times(2)).close();
}
@Test
void oracleSequenceMaxValueIncrementer() throws SQLException {
public void testOracleSequenceMaxValueIncrementer() throws SQLException {
given(dataSource.getConnection()).willReturn(connection);
given(connection.createStatement()).willReturn(statement);
given(statement.executeQuery("select myseq.nextval from dual")).willReturn(resultSet);
@@ -189,7 +185,7 @@ class DataFieldMaxValueIncrementerTests {
}
@Test
void postgresSequenceMaxValueIncrementer() throws SQLException {
public void testPostgresSequenceMaxValueIncrementer() throws SQLException {
given(dataSource.getConnection()).willReturn(connection);
given(connection.createStatement()).willReturn(statement);
given(statement.executeQuery("select nextval('myseq')")).willReturn(resultSet);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -179,23 +179,6 @@ public class CachingConnectionFactory extends SingleConnectionFactory {
}
/**
* Return a current session count, indicating the number of sessions currently
* cached by this connection factory.
* @since 5.3.7
*/
public int getCachedSessionCount() {
int count = 0;
synchronized (this.cachedSessions) {
for (Deque<Session> sessionList : this.cachedSessions.values()) {
synchronized (sessionList) {
count += sessionList.size();
}
}
}
return count;
}
/**
* Resets the Session cache as well.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,7 +30,6 @@ import io.rsocket.transport.ClientTransport;
import io.rsocket.transport.netty.client.TcpClientTransport;
import io.rsocket.transport.netty.client.WebsocketClientTransport;
import org.reactivestreams.Publisher;
import reactor.core.Disposable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -50,7 +49,7 @@ import org.springframework.util.MimeType;
* @author Brian Clozel
* @since 5.2
*/
public interface RSocketRequester extends Disposable {
public interface RSocketRequester {
/**
* Return the underlying {@link RSocketClient} used to make requests with.
@@ -111,27 +110,6 @@ public interface RSocketRequester extends Disposable {
*/
RequestSpec metadata(Object metadata, @Nullable MimeType mimeType);
/**
* Shortcut method that delegates to the same on the underlying
* {@link #rsocketClient()} in order to close the connection from the
* underlying transport and notify subscribers.
* @since 5.3.7
*/
@Override
default void dispose() {
rsocketClient().dispose();
}
/**
* Shortcut method that delegates to the same on the underlying
* {@link #rsocketClient()}.
* @since 5.3.7
*/
@Override
default boolean isDisposed() {
return rsocketClient().isDisposed();
}
/**
* Obtain a builder to create a client {@link RSocketRequester} by connecting
* to an RSocket server.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,16 +42,10 @@ public abstract class AbstractBrokerRegistration {
private final List<String> destinationPrefixes;
/**
* Create a new broker registration.
* @param clientInboundChannel the inbound channel
* @param clientOutboundChannel the outbound channel
* @param destinationPrefixes the destination prefixes
*/
public AbstractBrokerRegistration(SubscribableChannel clientInboundChannel,
MessageChannel clientOutboundChannel, @Nullable String[] destinationPrefixes) {
Assert.notNull(clientInboundChannel, "'clientInboundChannel' must not be null");
Assert.notNull(clientOutboundChannel, "'clientInboundChannel' must not be null");
Assert.notNull(clientOutboundChannel, "'clientOutboundChannel' must not be null");
this.clientInboundChannel = clientInboundChannel;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,16 +40,8 @@ public class SimpleBrokerRegistration extends AbstractBrokerRegistration {
private String selectorHeaderName = "selector";
/**
* Create a new {@code SimpleBrokerRegistration}.
* @param clientInboundChannel the inbound channel
* @param clientOutboundChannel the outbound channel
* @param destinationPrefixes the destination prefixes
*/
public SimpleBrokerRegistration(SubscribableChannel clientInboundChannel,
MessageChannel clientOutboundChannel, String[] destinationPrefixes) {
super(clientInboundChannel, clientOutboundChannel, destinationPrefixes);
public SimpleBrokerRegistration(SubscribableChannel inChannel, MessageChannel outChannel, String[] prefixes) {
super(inChannel, outChannel, prefixes);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -68,12 +68,6 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration {
private String userRegistryBroadcast;
/**
* Create a new {@code StompBrokerRelayRegistration}.
* @param clientInboundChannel the inbound channel
* @param clientOutboundChannel the outbound channel
* @param destinationPrefixes the destination prefixes
*/
public StompBrokerRelayRegistration(SubscribableChannel clientInboundChannel,
MessageChannel clientOutboundChannel, String[] destinationPrefixes) {
@@ -166,10 +166,7 @@ public class InvocableHandlerMethodTests {
@SuppressWarnings("unused")
static class Handler {
public Handler() {
}
private static class Handler {
public String handle(Integer intArg, String stringArg) {
return intArg + "-" + stringArg;
@@ -184,7 +181,7 @@ public class InvocableHandlerMethodTests {
}
static class ExceptionRaisingArgumentResolver implements HandlerMethodArgumentResolver {
private static class ExceptionRaisingArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
@@ -183,8 +183,6 @@ public class InvocableHandlerMethodTests {
private AtomicReference<String> result = new AtomicReference<>();
public Handler() {
}
public String getResult() {
return this.result.get();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -224,7 +224,8 @@ public abstract class AbstractContainerEntityManagerFactoryIntegrationTests
q.setFlushMode(FlushModeType.AUTO);
List<Person> people = q.getResultList();
assertThat(people.size()).isEqualTo(0);
assertThatExceptionOfType(Exception.class).isThrownBy(q::getSingleResult)
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
q.getSingleResult())
.withMessageContaining("closed");
// We would typically expect an IllegalStateException, but Hibernate throws a
// PersistenceException. So we assert the contents of the exception message instead.
+44 -12
View File
@@ -1,24 +1,56 @@
plugins {
id "org.unbroken-dome.xjc"
}
description = "Spring Object/XML Marshalling"
configurations {
jibx
xjc
}
dependencies {
jibx "org.jibx:jibx-bind:1.3.3"
jibx "org.apache.bcel:bcel:6.0"
xjc "javax.xml.bind:jaxb-api:2.3.1"
xjc "com.sun.xml.bind:jaxb-core:2.3.0.1"
xjc "com.sun.xml.bind:jaxb-impl:2.3.0.1"
xjc "com.sun.xml.bind:jaxb-xjc:2.3.1"
xjc "com.sun.activation:javax.activation:1.2.0"
}
xjc {
xjcVersion = '2.2'
}
sourceSets {
test {
xjcTargetPackage = 'org.springframework.oxm.jaxb.test'
ext.genSourcesDir = "${buildDir}/generated-sources"
ext.flightSchema = "${projectDir}/src/test/resources/org/springframework/oxm/flight.xsd"
task genJaxb {
ext.sourcesDir = "${genSourcesDir}/jaxb"
ext.classesDir = "${buildDir}/classes/jaxb"
inputs.files(flightSchema).withPathSensitivity(PathSensitivity.RELATIVE)
outputs.dir classesDir
doLast() {
project.ant {
taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask",
classpath: configurations.xjc.asPath
mkdir(dir: sourcesDir)
mkdir(dir: classesDir)
xjc(destdir: sourcesDir, schema: flightSchema,
package: "org.springframework.oxm.jaxb.test") {
produces(dir: sourcesDir, includes: "**/*.java")
}
javac(destdir: classesDir, source: 1.8, target: 1.8, debug: true,
debugLevel: "lines,vars,source",
classpath: configurations.xjc.asPath) {
src(path: sourcesDir)
include(name: "**/*.java")
include(name: "*.java")
}
copy(todir: classesDir) {
fileset(dir: sourcesDir, erroronmissingdir: false) {
exclude(name: "**/*.java")
}
}
}
}
}
@@ -35,7 +67,7 @@ dependencies {
testCompile("org.codehaus.jettison:jettison") {
exclude group: "stax", module: "stax-api"
}
//testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
testCompile("org.xmlunit:xmlunit-assertj")
testCompile("org.xmlunit:xmlunit-matchers")
testRuntime("com.sun.xml.bind:jaxb-core")
@@ -44,7 +76,7 @@ dependencies {
// JiBX compiler is currently not compatible with JDK 9+.
// If customJavaHome has been set, we assume the custom JDK version is 9+.
if ((JavaVersion.current() == JavaVersion.VERSION_1_8) && !project.hasProperty("testToolchain")) {
if ((JavaVersion.current() == JavaVersion.VERSION_1_8) && !System.getProperty("customJavaSourceVersion")) {
compileTestJava {
def bindingXml = "${projectDir}/src/test/resources/org/springframework/oxm/jibx/binding.xml"
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -78,7 +78,7 @@ import static org.xmlunit.diff.DifferenceEvaluators.downgradeDifferencesToEqual;
* @author Biju Kunjummen
* @author Sam Brannen
*/
class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
public class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
private static final String CONTEXT_PATH = "org.springframework.oxm.jaxb.test";
@@ -104,7 +104,7 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
@Test
void marshalSAXResult() throws Exception {
public void marshalSAXResult() throws Exception {
ContentHandler contentHandler = mock(ContentHandler.class);
SAXResult result = new SAXResult(contentHandler);
marshaller.marshal(flights, result);
@@ -124,7 +124,7 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
}
@Test
void lazyInit() throws Exception {
public void lazyInit() throws Exception {
marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(CONTEXT_PATH);
marshaller.setLazyInit(true);
@@ -137,44 +137,48 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
}
@Test
void properties() throws Exception {
public void properties() throws Exception {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(CONTEXT_PATH);
marshaller.setMarshallerProperties(
Collections.singletonMap(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE));
Collections.<String, Object>singletonMap(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE));
marshaller.afterPropertiesSet();
}
@Test
void noContextPathOrClassesToBeBound() throws Exception {
public void noContextPathOrClassesToBeBound() throws Exception {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
assertThatIllegalArgumentException().isThrownBy(marshaller::afterPropertiesSet);
assertThatIllegalArgumentException().isThrownBy(
marshaller::afterPropertiesSet);
}
@Test
void testInvalidContextPath() throws Exception {
public void testInvalidContextPath() throws Exception {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("ab");
assertThatExceptionOfType(UncategorizedMappingException.class).isThrownBy(marshaller::afterPropertiesSet);
assertThatExceptionOfType(UncategorizedMappingException.class).isThrownBy(
marshaller::afterPropertiesSet);
}
@Test
void marshalInvalidClass() throws Exception {
public void marshalInvalidClass() throws Exception {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(FlightType.class);
marshaller.afterPropertiesSet();
Result result = new StreamResult(new StringWriter());
Flights flights = new Flights();
assertThatExceptionOfType(XmlMappingException.class).isThrownBy(() -> marshaller.marshal(flights, result));
assertThatExceptionOfType(XmlMappingException.class).isThrownBy(() ->
marshaller.marshal(flights, result));
}
@Test
void supportsContextPath() throws Exception {
public void supportsContextPath() throws Exception {
testSupports();
}
@Test
void supportsClassesToBeBound() throws Exception {
public void supportsClassesToBeBound() throws Exception {
marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(Flights.class, FlightType.class);
marshaller.afterPropertiesSet();
@@ -182,7 +186,7 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
}
@Test
void supportsPackagesToScan() throws Exception {
public void supportsPackagesToScan() throws Exception {
marshaller = new Jaxb2Marshaller();
marshaller.setPackagesToScan(CONTEXT_PATH);
marshaller.afterPropertiesSet();
@@ -220,11 +224,11 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
private void testSupportsPrimitives() {
final Primitives primitives = new Primitives();
ReflectionUtils.doWithMethods(Primitives.class, method -> {
ReflectionUtils.doWithMethods(Primitives.class, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Type returnType = method.getGenericReturnType();
assertThat(marshaller.supports(returnType))
.as("Jaxb2Marshaller does not support JAXBElement<" + method.getName().substring(9) + ">")
.isTrue();
assertThat(marshaller.supports(returnType)).as("Jaxb2Marshaller does not support JAXBElement<" + method.getName().substring(9) + ">").isTrue();
try {
// make sure the marshalling does not result in errors
Object returnValue = method.invoke(primitives);
@@ -233,18 +237,22 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
catch (InvocationTargetException e) {
throw new AssertionError(e.getMessage(), e);
}
},
method -> method.getName().startsWith("primitive")
);
}
}, new ReflectionUtils.MethodFilter() {
@Override
public boolean matches(Method method) {
return method.getName().startsWith("primitive");
}
});
}
private void testSupportsStandardClasses() throws Exception {
final StandardClasses standardClasses = new StandardClasses();
ReflectionUtils.doWithMethods(StandardClasses.class, method -> {
ReflectionUtils.doWithMethods(StandardClasses.class, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Type returnType = method.getGenericReturnType();
assertThat(marshaller.supports(returnType))
.as("Jaxb2Marshaller does not support JAXBElement<" + method.getName().substring(13) + ">")
.isTrue();
assertThat(marshaller.supports(returnType)).as("Jaxb2Marshaller does not support JAXBElement<" + method.getName().substring(13) + ">").isTrue();
try {
// make sure the marshalling does not result in errors
Object returnValue = method.invoke(standardClasses);
@@ -253,13 +261,17 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
catch (InvocationTargetException e) {
throw new AssertionError(e.getMessage(), e);
}
},
method -> method.getName().startsWith("standardClass")
);
}
}, new ReflectionUtils.MethodFilter() {
@Override
public boolean matches(Method method) {
return method.getName().startsWith("standardClass");
}
});
}
@Test
void supportsXmlRootElement() throws Exception {
public void supportsXmlRootElement() throws Exception {
marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(DummyRootElement.class, DummyType.class);
marshaller.afterPropertiesSet();
@@ -272,7 +284,7 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
@Test
void marshalAttachments() throws Exception {
public void marshalAttachments() throws Exception {
marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(BinaryObject.class);
marshaller.setMtomEnabled(true);
@@ -292,7 +304,7 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
}
@Test // SPR-10714
void marshalAWrappedObjectHoldingAnXmlElementDeclElement() throws Exception {
public void marshalAWrappedObjectHoldingAnXmlElementDeclElement() throws Exception {
marshaller = new Jaxb2Marshaller();
marshaller.setPackagesToScan("org.springframework.oxm.jaxb");
marshaller.afterPropertiesSet();
@@ -306,7 +318,7 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
}
@Test // SPR-10806
void unmarshalStreamSourceWithXmlOptions() throws Exception {
public void unmarshalStreamSourceWithXmlOptions() throws Exception {
final javax.xml.bind.Unmarshaller unmarshaller = mock(javax.xml.bind.Unmarshaller.class);
Jaxb2Marshaller marshaller = new Jaxb2Marshaller() {
@Override
@@ -340,7 +352,7 @@ class Jaxb2MarshallerTests extends AbstractMarshallerTests<Jaxb2Marshaller> {
}
@Test // SPR-10806
void unmarshalSaxSourceWithXmlOptions() throws Exception {
public void unmarshalSaxSourceWithXmlOptions() throws Exception {
final javax.xml.bind.Unmarshaller unmarshaller = mock(javax.xml.bind.Unmarshaller.class);
Jaxb2Marshaller marshaller = new Jaxb2Marshaller() {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -31,7 +31,6 @@ import javax.xml.transform.stream.StreamSource;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.oxm.AbstractUnmarshallerTests;
import org.springframework.oxm.jaxb.test.FlightType;
@@ -57,7 +56,7 @@ public class Jaxb2UnmarshallerTests extends AbstractUnmarshallerTests<Jaxb2Marsh
protected Jaxb2Marshaller createUnmarshaller() throws Exception {
Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
unmarshaller.setContextPath("org.springframework.oxm.jaxb.test");
unmarshaller.setSchema(new FileSystemResource("src/test/schema/flight.xsd"));
unmarshaller.setSchema(new ClassPathResource("org/springframework/oxm/flight.xsd"));
unmarshaller.afterPropertiesSet();
return unmarshaller;
}
@@ -1,20 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2021 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://samples.springframework.org/flight"
xmlns:tns="http://samples.springframework.org/flight">
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="https://samples.springframework.org/order"
xmlns:tns="https://samples.springframework.org/order">
<element name="order">
<complexType>
<sequence>
<element name="order-item" type="tns:orderItemType"
maxOccurs="unbounded">
</element>
</sequence>
</complexType>
</element>
<complexType name="orderItemType">
<attribute name="id" type="string" />
<attribute name="quantity" type="int" />
</complexType>
</schema>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -315,8 +315,8 @@ public class MockServletContext implements ServletContext {
return resourcePaths;
}
catch (InvalidPathException | IOException ex ) {
if (logger.isDebugEnabled()) {
logger.debug("Could not get resource paths for " +
if (logger.isWarnEnabled()) {
logger.warn("Could not get resource paths for " +
(resource != null ? resource : resourceLocation), ex);
}
return null;
@@ -339,8 +339,8 @@ public class MockServletContext implements ServletContext {
throw ex;
}
catch (InvalidPathException | IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not get URL for resource " +
if (logger.isWarnEnabled()) {
logger.warn("Could not get URL for resource " +
(resource != null ? resource : resourceLocation), ex);
}
return null;
@@ -360,8 +360,8 @@ public class MockServletContext implements ServletContext {
return resource.getInputStream();
}
catch (InvalidPathException | IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not open InputStream for resource " +
if (logger.isWarnEnabled()) {
logger.warn("Could not open InputStream for resource " +
(resource != null ? resource : resourceLocation), ex);
}
return null;
@@ -476,8 +476,8 @@ public class MockServletContext implements ServletContext {
return resource.getFile().getAbsolutePath();
}
catch (InvalidPathException | IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not determine real path of resource " +
if (logger.isWarnEnabled()) {
logger.warn("Could not determine real path of resource " +
(resource != null ? resource : resourceLocation), ex);
}
return null;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2017 the original author 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,9 +34,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
import org.springframework.test.context.TestContextAnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -108,7 +105,6 @@ abstract class AbstractExpressionEvaluatingCondition implements ExecutionConditi
boolean loadContext = loadContextExtractor.apply(annotation.get());
boolean evaluatedToTrue = evaluateExpression(expression, loadContext, annotationType, context);
ConditionEvaluationResult result;
if (evaluatedToTrue) {
String adjective = (enabledOnTrue ? "enabled" : "disabled");
@@ -118,7 +114,7 @@ abstract class AbstractExpressionEvaluatingCondition implements ExecutionConditi
if (logger.isInfoEnabled()) {
logger.info(reason);
}
result = (enabledOnTrue ? ConditionEvaluationResult.enabled(reason)
return (enabledOnTrue ? ConditionEvaluationResult.enabled(reason)
: ConditionEvaluationResult.disabled(reason));
}
else {
@@ -128,26 +124,9 @@ abstract class AbstractExpressionEvaluatingCondition implements ExecutionConditi
if (logger.isDebugEnabled()) {
logger.debug(reason);
}
result = (enabledOnTrue ? ConditionEvaluationResult.disabled(reason) :
return (enabledOnTrue ? ConditionEvaluationResult.disabled(reason) :
ConditionEvaluationResult.enabled(reason));
}
// If we eagerly loaded the ApplicationContext to evaluate SpEL expressions
// and the test class ends up being disabled, we have to check if the
// user asked for the ApplicationContext to be closed via @DirtiesContext,
// since the DirtiesContextTestExecutionListener will never be invoked for
// a disabled test class.
// See https://github.com/spring-projects/spring-framework/issues/26694
if (loadContext && result.isDisabled() && element instanceof Class) {
Class<?> testClass = (Class<?>) element;
DirtiesContext dirtiesContext = TestContextAnnotationUtils.findMergedAnnotation(testClass, DirtiesContext.class);
if (dirtiesContext != null) {
HierarchyMode hierarchyMode = dirtiesContext.hierarchyMode();
SpringExtension.getTestContextManager(context).getTestContext().markApplicationContextDirty(hierarchyMode);
}
}
return result;
}
private <A extends Annotation> boolean evaluateExpression(String expression, boolean loadContext,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -287,7 +287,7 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
* Get the {@link TestContextManager} associated with the supplied {@code ExtensionContext}.
* @return the {@code TestContextManager} (never {@code null})
*/
static TestContextManager getTestContextManager(ExtensionContext context) {
private static TestContextManager getTestContextManager(ExtensionContext context) {
Assert.notNull(context, "ExtensionContext must not be null");
Class<?> testClass = context.getRequiredTestClass();
Store store = getStore(context);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -373,16 +373,8 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable {
for (NameValuePair param : this.webRequest.getRequestParameters()) {
if (param instanceof KeyDataPair) {
KeyDataPair pair = (KeyDataPair) param;
File file = pair.getFile();
MockPart part;
if (file != null) {
part = new MockPart(pair.getName(), file.getName(), readAllBytes(file));
part.getHeaders().setContentType(MediaType.valueOf(pair.getMimeType()));
}
else { // mimic empty file upload
part = new MockPart(pair.getName(), "", null);
part.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
}
MockPart part = new MockPart(pair.getName(), pair.getFile().getName(), readAllBytes(pair.getFile()));
part.getHeaders().setContentType(MediaType.valueOf(pair.getMimeType()));
request.addPart(part);
}
else {
@@ -496,6 +496,7 @@ class MockHttpServletResponseTests {
String expiryDate = "Tue, 8 Oct 2019 19:50:00 GMT";
String cookieValue = "SESSION=123; Path=/; Expires=" + expiryDate;
response.addHeader(SET_COOKIE, cookieValue);
System.err.println(response.getCookie("SESSION"));
assertThat(response.getHeader(SET_COOKIE)).isEqualTo(cookieValue);
assertNumCookies(1);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -557,10 +557,10 @@ class TestContextAnnotationUtilsTests {
@Target(ElementType.TYPE)
@interface MetaConfig {
class DevConfig {
static class DevConfig {
}
class ProductionConfig {
static class ProductionConfig {
}
@@ -607,11 +607,11 @@ class TestContextAnnotationUtilsTests {
}
@MetaConfig
static class MetaConfigWithDefaultAttributesTestCase {
class MetaConfigWithDefaultAttributesTestCase {
}
@MetaConfig(classes = TestContextAnnotationUtilsTests.class)
static class MetaConfigWithOverriddenAttributesTestCase {
class MetaConfigWithOverriddenAttributesTestCase {
}
// -------------------------------------------------------------------------
@@ -1,107 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit.jupiter;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.platform.testkit.engine.EngineTestKit;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
/**
* Integration tests which verify support for {@link DisabledIf @DisabledIf} in
* conjunction with {@link DirtiesContext @DirtiesContext} and the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.2.14
* @see EnabledIfAndDirtiesContextTests
*/
class DisabledIfAndDirtiesContextTests {
private static AtomicBoolean contextClosed = new AtomicBoolean();
@BeforeEach
void reset() {
contextClosed.set(false);
}
@Test
void contextShouldBeClosedForEnabledTestClass() {
assertThat(contextClosed).as("context closed").isFalse();
EngineTestKit.engine("junit-jupiter").selectors(
selectClass(EnabledAndDirtiesContextTestCase.class))//
.execute()//
.testEvents()//
.assertStatistics(stats -> stats.started(1).succeeded(1).failed(0));
assertThat(contextClosed).as("context closed").isTrue();
}
@Test
void contextShouldBeClosedForDisabledTestClass() {
assertThat(contextClosed).as("context closed").isFalse();
EngineTestKit.engine("junit-jupiter").selectors(
selectClass(DisabledAndDirtiesContextTestCase.class))//
.execute()//
.testEvents()//
.assertStatistics(stats -> stats.started(0).succeeded(0).failed(0));
assertThat(contextClosed).as("context closed").isTrue();
}
@SpringJUnitConfig(Config.class)
@DisabledIf(expression = "false", loadContext = true)
@DirtiesContext
static class EnabledAndDirtiesContextTestCase {
@Test
void test() {
/* no-op */
}
}
@SpringJUnitConfig(Config.class)
@DisabledIf(expression = "true", loadContext = true)
@DirtiesContext
static class DisabledAndDirtiesContextTestCase {
@Test
void test() {
fail("This test must be disabled");
}
}
@Configuration
static class Config {
@Bean
DisposableBean disposableBean() {
return () -> contextClosed.set(true);
}
}
}
@@ -1,107 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit.jupiter;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.platform.testkit.engine.EngineTestKit;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
/**
* Integration tests which verify support for {@link EnabledIf @EnabledIf} in
* conjunction with {@link DirtiesContext @DirtiesContext} and the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.2.14
* @see DisabledIfAndDirtiesContextTests
*/
class EnabledIfAndDirtiesContextTests {
private static AtomicBoolean contextClosed = new AtomicBoolean();
@BeforeEach
void reset() {
contextClosed.set(false);
}
@Test
void contextShouldBeClosedForEnabledTestClass() {
assertThat(contextClosed).as("context closed").isFalse();
EngineTestKit.engine("junit-jupiter").selectors(
selectClass(EnabledAndDirtiesContextTestCase.class))//
.execute()//
.testEvents()//
.assertStatistics(stats -> stats.started(1).succeeded(1).failed(0));
assertThat(contextClosed).as("context closed").isTrue();
}
@Test
void contextShouldBeClosedForDisabledTestClass() {
assertThat(contextClosed).as("context closed").isFalse();
EngineTestKit.engine("junit-jupiter").selectors(
selectClass(DisabledAndDirtiesContextTestCase.class))//
.execute()//
.testEvents()//
.assertStatistics(stats -> stats.started(0).succeeded(0).failed(0));
assertThat(contextClosed).as("context closed").isTrue();
}
@SpringJUnitConfig(Config.class)
@EnabledIf(expression = "true", loadContext = true)
@DirtiesContext
static class EnabledAndDirtiesContextTestCase {
@Test
void test() {
/* no-op */
}
}
@SpringJUnitConfig(Config.class)
@EnabledIf(expression = "false", loadContext = true)
@DirtiesContext
static class DisabledAndDirtiesContextTestCase {
@Test
void test() {
fail("This test must be disabled");
}
}
@Configuration
static class Config {
@Bean
DisposableBean disposableBean() {
return () -> contextClosed.set(true);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,7 @@ class TimedTransactionalSpringExtensionTests {
event(test("WithExceededJUnitJupiterTimeout"),
finishedWithFailure(
instanceOf(TimeoutException.class),
message(msg -> msg.endsWith("timed out after 10 milliseconds")))));
message(msg -> msg.endsWith("timed out after 50 milliseconds")))));
}
@@ -83,10 +83,10 @@ class TimedTransactionalSpringExtensionTests {
}
@Test
@Timeout(value = 10, unit = TimeUnit.MILLISECONDS)
@Timeout(value = 50, unit = TimeUnit.MILLISECONDS)
void transactionalWithExceededJUnitJupiterTimeout() throws Exception {
assertThatTransaction().isActive();
Thread.sleep(200);
Thread.sleep(100);
}
@Test
@@ -97,11 +97,11 @@ class TimedTransactionalSpringExtensionTests {
}
@Test
@Timeout(value = 10, unit = TimeUnit.MILLISECONDS)
@Timeout(value = 50, unit = TimeUnit.MILLISECONDS)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
void notTransactionalWithExceededJUnitJupiterTimeout() throws Exception {
assertThatTransaction().isNotActive();
Thread.sleep(200);
Thread.sleep(100);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -76,14 +76,14 @@ public class TimedSpringRunnerTests {
}
// Should Fail due to timeout.
@Test(timeout = 10)
@Test(timeout = 100)
public void jUnitTimeoutWithSleep() throws Exception {
Thread.sleep(200);
}
// Should Fail due to timeout.
@Test
@Timed(millis = 10)
@Timed(millis = 100)
public void springTimeoutWithSleep() throws Exception {
Thread.sleep(200);
}
@@ -97,7 +97,7 @@ public class TimedSpringRunnerTests {
// Should Fail due to timeout.
@Test
@MetaTimedWithOverride(millis = 10)
@MetaTimedWithOverride(millis = 100)
public void springTimeoutWithSleepAndMetaAnnotationAndOverride() throws Exception {
Thread.sleep(200);
}
@@ -110,7 +110,7 @@ public class TimedSpringRunnerTests {
}
}
@Timed(millis = 10)
@Timed(millis = 100)
@Retention(RetentionPolicy.RUNTIME)
private static @interface MetaTimed {
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,10 +16,8 @@
package org.springframework.test.web.servlet.htmlunit;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
@@ -54,7 +52,6 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
/**
@@ -426,7 +423,8 @@ public class HtmlUnitRequestBuilderTests {
}
@Test // gh-24926
public void buildRequestParameterMapViaWebRequestDotSetRequestParametersWithFileToUploadAsParameter() throws Exception {
public void buildRequestParameterMapViaWebRequestDotSetFileToUploadAsParameter() throws Exception {
webRequest.setRequestParameters(Collections.singletonList(
new KeyDataPair("key",
new ClassPathResource("org/springframework/test/web/htmlunit/test.txt").getFile(),
@@ -434,7 +432,7 @@ public class HtmlUnitRequestBuilderTests {
MockHttpServletRequest actualRequest = requestBuilder.buildRequest(servletContext);
assertThat(actualRequest.getParts()).hasSize(1);
assertThat(actualRequest.getParts().size()).isEqualTo(1);
Part part = actualRequest.getPart("key");
assertThat(part).isNotNull();
assertThat(part.getName()).isEqualTo("key");
@@ -443,30 +441,6 @@ public class HtmlUnitRequestBuilderTests {
assertThat(part.getContentType()).isEqualTo(MimeType.TEXT_PLAIN);
}
@Test // gh-26799
public void buildRequestParameterMapViaWebRequestDotSetRequestParametersWithNullFileToUploadAsParameter() throws Exception {
webRequest.setRequestParameters(Collections.singletonList(new KeyDataPair("key", null, null, null, (Charset) null)));
MockHttpServletRequest actualRequest = requestBuilder.buildRequest(servletContext);
assertThat(actualRequest.getParts()).hasSize(1);
Part part = actualRequest.getPart("key");
assertSoftly(softly -> {
softly.assertThat(part).isNotNull();
softly.assertThat(part.getName()).as("name").isEqualTo("key");
softly.assertThat(part.getSize()).as("size").isEqualTo(0);
try {
softly.assertThat(part.getInputStream()).isEmpty();
}
catch (IOException ex) {
softly.fail("failed to get InputStream", ex);
}
softly.assertThat(part.getSubmittedFileName()).as("filename").isEqualTo("");
softly.assertThat(part.getContentType()).as("content-type").isEqualTo("application/octet-stream");
});
}
@Test
public void buildRequestParameterMapFromSingleQueryParam() throws Exception {
webRequest.setUrl(new URL("https://example.com/example/?name=value"));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -32,7 +32,6 @@ import org.springframework.test.web.servlet.client.MockMvcWebTestClient;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@@ -100,7 +99,7 @@ public class AsyncTests {
}
@Test
public void deferredResultWithImmediateValue() {
public void deferredResultWithImmediateValue() throws Exception {
this.testClient.get()
.uri("/1?deferredResultWithImmediateValue=true")
.exchange()
@@ -110,7 +109,7 @@ public class AsyncTests {
}
@Test
public void deferredResultWithDelayedError() {
public void deferredResultWithDelayedError() throws Exception {
this.testClient.get()
.uri("/1?deferredResultWithDelayedError=true")
.exchange()
@@ -119,7 +118,7 @@ public class AsyncTests {
}
@Test
public void listenableFuture() {
public void listenableFuture() throws Exception {
this.testClient.get()
.uri("/1?listenableFuture=true")
.exchange()
@@ -143,17 +142,17 @@ public class AsyncTests {
@RequestMapping(path = "/{id}", produces = "application/json")
private static class AsyncController {
@GetMapping(params = "callable")
@RequestMapping(params = "callable")
public Callable<Person> getCallable() {
return () -> new Person("Joe");
}
@GetMapping(params = "streaming")
@RequestMapping(params = "streaming")
public StreamingResponseBody getStreaming() {
return os -> os.write("name=Joe".getBytes(StandardCharsets.UTF_8));
}
@GetMapping(params = "streamingSlow")
@RequestMapping(params = "streamingSlow")
public StreamingResponseBody getStreamingSlow() {
return os -> {
os.write("name=Joe".getBytes());
@@ -167,41 +166,41 @@ public class AsyncTests {
};
}
@GetMapping(params = "streamingJson")
@RequestMapping(params = "streamingJson")
public ResponseEntity<StreamingResponseBody> getStreamingJson() {
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON)
.body(os -> os.write("{\"name\":\"Joe\",\"someDouble\":0.5}".getBytes(StandardCharsets.UTF_8)));
}
@GetMapping(params = "deferredResult")
@RequestMapping(params = "deferredResult")
public DeferredResult<Person> getDeferredResult() {
DeferredResult<Person> result = new DeferredResult<>();
delay(100, () -> result.setResult(new Person("Joe")));
return result;
}
@GetMapping(params = "deferredResultWithImmediateValue")
@RequestMapping(params = "deferredResultWithImmediateValue")
public DeferredResult<Person> getDeferredResultWithImmediateValue() {
DeferredResult<Person> result = new DeferredResult<>();
result.setResult(new Person("Joe"));
return result;
}
@GetMapping(params = "deferredResultWithDelayedError")
@RequestMapping(params = "deferredResultWithDelayedError")
public DeferredResult<Person> getDeferredResultWithDelayedError() {
DeferredResult<Person> result = new DeferredResult<>();
delay(100, () -> result.setErrorResult(new RuntimeException("Delayed Error")));
return result;
}
@GetMapping(params = "listenableFuture")
@RequestMapping(params = "listenableFuture")
public ListenableFuture<Person> getListenableFuture() {
ListenableFutureTask<Person> futureTask = new ListenableFutureTask<>(() -> new Person("Joe"));
delay(100, futureTask);
return futureTask;
}
@GetMapping(params = "completableFutureWithImmediateValue")
@RequestMapping(params = "completableFutureWithImmediateValue")
public CompletableFuture<Person> getCompletableFutureWithImmediateValue() {
CompletableFuture<Person> future = new CompletableFuture<>();
future.complete(new Person("Joe"));
@@ -1,71 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.web.servlet.samples.client.standalone;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import org.springframework.test.web.Person;
import org.springframework.test.web.reactive.server.FluxExchangeResult;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.servlet.client.MockMvcWebTestClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import static java.time.Duration.ofMillis;
import static org.assertj.core.api.Assertions.assertThat;
/**
* SSE controller tests with MockMvc and WebTestClient.
*
* @author Rossen Stoyanchev
*/
public class SseTests {
private final WebTestClient testClient =
MockMvcWebTestClient.bindToController(new SseController()).build();
@Test
public void sse() {
FluxExchangeResult<Person> exchangeResult = this.testClient.get()
.uri("/persons")
.exchange()
.expectStatus().isOk()
.expectHeader().contentType("text/event-stream")
.returnResult(Person.class);
StepVerifier.create(exchangeResult.getResponseBody())
.expectNext(new Person("N0"), new Person("N1"), new Person("N2"))
.expectNextCount(4)
.consumeNextWith(person -> assertThat(person.getName()).endsWith("7"))
.thenCancel()
.verify();
}
@RestController
private static class SseController {
@GetMapping(path = "/persons", produces = "text/event-stream")
public Flux<Person> getPersonStream() {
return Flux.interval(ofMillis(100)).take(50).onBackpressureBuffer(50)
.map(index -> new Person("N" + index));
}
}
}
@@ -25,7 +25,6 @@
<Logger name="org.springframework.test.context.support.DelegatingSmartContextLoader" level="info" />
<Logger name="org.springframework.test.context.support.AbstractGenericContextLoader" level="info" />
<Logger name="org.springframework.test.context.support.AnnotationConfigContextLoader" level="info" />
<Logger name="org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener" level="warn" />
<Logger name="org.springframework.test.context.support.TestPropertySourceUtils" level="trace" />
<Logger name="org.springframework.beans" level="warn" />
<Logger name="org.springframework.test.web.servlet.result" level="debug" />
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.OrderComparator;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -320,7 +320,7 @@ public abstract class TransactionSynchronizationManager {
else {
// Sort lazily here, not in registerSynchronization.
List<TransactionSynchronization> sortedSynchs = new ArrayList<>(synchs);
OrderComparator.sort(sortedSynchs);
AnnotationAwareOrderComparator.sort(sortedSynchs);
return Collections.unmodifiableList(sortedSynchs);
}
}
-2
View File
@@ -7,7 +7,6 @@ dependencies {
compile(project(":spring-beans"))
compile(project(":spring-core"))
compileOnly(project(":kotlin-coroutines"))
compileOnly("io.projectreactor.tools:blockhound")
optional(project(":spring-aop"))
optional(project(":spring-context"))
optional(project(":spring-oxm"))
@@ -76,7 +75,6 @@ dependencies {
testCompile("org.skyscreamer:jsonassert")
testCompile("org.xmlunit:xmlunit-assertj")
testCompile("org.xmlunit:xmlunit-matchers")
testCompile("io.projectreactor.tools:blockhound")
testRuntime("com.sun.mail:javax.mail")
testRuntime("com.sun.xml.bind:jaxb-core")
testRuntime("com.sun.xml.bind:jaxb-impl")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -99,12 +99,6 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
* @see <a href="https://tools.ietf.org/html/rfc7231#section-5.3.5">Section 5.3.5 of RFC 7231</a>
*/
public static final String ACCEPT_LANGUAGE = "Accept-Language";
/**
* The HTTP {@code Accept-Patch} header field name.
* @since 5.3.6
* @see <a href="https://tools.ietf.org/html/rfc5789#section-3.1">Section 3.1 of RFC 5789</a>
*/
public static final String ACCEPT_PATCH = "Accept-Patch";
/**
* The HTTP {@code Accept-Ranges} header field name.
* @see <a href="https://tools.ietf.org/html/rfc7233#section-2.3">Section 5.3.5 of RFC 7233</a>
@@ -531,25 +525,6 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
.collect(Collectors.toList());
}
/**
* Set the list of acceptable {@linkplain MediaType media types} for
* {@code PATCH} methods, as specified by the {@code Accept-Patch} header.
* @since 5.3.6
*/
public void setAcceptPatch(List<MediaType> mediaTypes) {
set(ACCEPT_PATCH, MediaType.toString(mediaTypes));
}
/**
* Return the list of acceptable {@linkplain MediaType media types} for
* {@code PATCH} methods, as specified by the {@code Accept-Patch} header.
* <p>Returns an empty list when the acceptable media types are unspecified.
* @since 5.3.6
*/
public List<MediaType> getAcceptPatch() {
return MediaType.parseMediaTypes(get(ACCEPT_PATCH));
}
/**
* Set the (new) value of the {@code Access-Control-Allow-Credentials} response header.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,13 +57,14 @@ public enum HttpMethod {
/**
* Determine whether this {@code HttpMethod} matches the given method value.
* @param method the HTTP method as a String
* Determine whether this {@code HttpMethod} matches the given
* method value.
* @param method the method value as a String
* @return {@code true} if it matches, {@code false} otherwise
* @since 4.2.4
*/
public boolean matches(String method) {
return name().equals(method);
return (this == resolve(method));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -416,13 +416,6 @@ public enum HttpStatus {
NETWORK_AUTHENTICATION_REQUIRED(511, Series.SERVER_ERROR, "Network Authentication Required");
private static final HttpStatus[] VALUES;
static {
VALUES = values();
}
private final int value;
private final Series series;
@@ -557,8 +550,7 @@ public enum HttpStatus {
*/
@Nullable
public static HttpStatus resolve(int statusCode) {
// used cached VALUES instead of values() to prevent array allocation
for (HttpStatus status : VALUES) {
for (HttpStatus status : values()) {
if (status.value == statusCode) {
return status;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,6 @@ import java.util.Optional;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
@@ -66,7 +65,6 @@ public final class MediaTypeFactory {
*/
private static MultiValueMap<String, MediaType> parseMimeTypes() {
InputStream is = MediaTypeFactory.class.getResourceAsStream(MIME_TYPES_FILE_NAME);
Assert.state(is != null, MIME_TYPES_FILE_NAME + " not found in classpath");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.US_ASCII))) {
MultiValueMap<String, MediaType> result = new LinkedMultiValueMap<>();
String line;
@@ -84,7 +82,7 @@ public final class MediaTypeFactory {
return result;
}
catch (IOException ex) {
throw new IllegalStateException("Could not read " + MIME_TYPES_FILE_NAME, ex);
throw new IllegalStateException("Could not load '" + MIME_TYPES_FILE_NAME + "'", ex);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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.
@@ -18,6 +18,7 @@ package org.springframework.http.codec;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -170,14 +171,12 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
if (this.encoder == null) {
throw new CodecException("No SSE encoder configured and the data is not String.");
}
return Flux.defer(() -> {
DataBuffer startBuffer = encodeText(eventContent, mediaType, factory);
DataBuffer endBuffer = encodeText("\n\n", mediaType, factory);
DataBuffer dataBuffer = ((Encoder<T>) this.encoder).encodeValue(data, factory, dataType, mediaType, hints);
Hints.touchDataBuffer(dataBuffer, hints, logger);
return Flux.just(startBuffer, dataBuffer, endBuffer);
});
DataBuffer buffer = ((Encoder<T>) this.encoder).encodeValue(data, factory, dataType, mediaType, hints);
Hints.touchDataBuffer(buffer, hints, logger);
return Flux.just(factory.join(Arrays.asList(
encodeText(eventContent, mediaType, factory),
buffer,
encodeText("\n\n", mediaType, factory))));
}
private void writeField(String fieldName, Object fieldValue, StringBuilder sb) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,9 +17,10 @@
package org.springframework.http.codec.multipart;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -61,6 +62,8 @@ import org.springframework.util.Assert;
*/
public class DefaultPartHttpMessageReader extends LoggingCodecSupport implements HttpMessageReader<Part> {
private static final String IDENTIFIER = "spring-multipart";
private int maxInMemorySize = 256 * 1024;
private int maxHeadersSize = 8 * 1024;
@@ -73,9 +76,7 @@ public class DefaultPartHttpMessageReader extends LoggingCodecSupport implements
private Scheduler blockingOperationScheduler = Schedulers.boundedElastic();
private FileStorage fileStorage = FileStorage.tempDirectory(this::getBlockingOperationScheduler);
private Charset headersCharset = StandardCharsets.UTF_8;
private Mono<Path> fileStorageDirectory = Mono.defer(this::defaultFileStorageDirectory).cache();
/**
@@ -131,7 +132,7 @@ public class DefaultPartHttpMessageReader extends LoggingCodecSupport implements
}
/**
* Set the directory used to store parts larger than
* Sets the directory used to store parts larger than
* {@link #setMaxInMemorySize(int) maxInMemorySize}. By default, a directory
* named {@code spring-webflux-multipart} is created under the system
* temporary directory.
@@ -143,11 +144,14 @@ public class DefaultPartHttpMessageReader extends LoggingCodecSupport implements
*/
public void setFileStorageDirectory(Path fileStorageDirectory) throws IOException {
Assert.notNull(fileStorageDirectory, "FileStorageDirectory must not be null");
this.fileStorage = FileStorage.fromPath(fileStorageDirectory);
if (!Files.exists(fileStorageDirectory)) {
Files.createDirectory(fileStorageDirectory);
}
this.fileStorageDirectory = Mono.just(fileStorageDirectory);
}
/**
* Set the Reactor {@link Scheduler} to be used for creating files and
* Sets the Reactor {@link Scheduler} to be used for creating files and
* directories, and writing to files. By default,
* {@link Schedulers#boundedElastic()} is used, but this property allows for
* changing it to an externally managed scheduler.
@@ -161,21 +165,19 @@ public class DefaultPartHttpMessageReader extends LoggingCodecSupport implements
this.blockingOperationScheduler = blockingOperationScheduler;
}
private Scheduler getBlockingOperationScheduler() {
return this.blockingOperationScheduler;
}
/**
* When set to {@code true}, the {@linkplain Part#content() part content}
* is streamed directly from the parsed input buffer stream, and not stored
* in memory nor file.
* When {@code false}, parts are backed by
* in-memory and/or file storage. Defaults to {@code false}.
*
* <p><strong>NOTE</strong> that with streaming enabled, the
* {@code Flux<Part>} that is produced by this message reader must be
* consumed in the original order, i.e. the order of the HTTP message.
* Additionally, the {@linkplain Part#content() body contents} must either
* be completely consumed or canceled before moving to the next part.
*
* <p>Also note that enabling this property effectively ignores
* {@link #setMaxInMemorySize(int) maxInMemorySize},
* {@link #setMaxDiskUsagePerPart(long) maxDiskUsagePerPart},
@@ -186,18 +188,6 @@ public class DefaultPartHttpMessageReader extends LoggingCodecSupport implements
this.streaming = streaming;
}
/**
* Set the character set used to decode headers.
* Defaults to UTF-8 as per RFC 7578.
* @param headersCharset the charset to use for decoding headers
* @since 5.3.6
* @see <a href="https://tools.ietf.org/html/rfc7578#section-5.1">RFC-7578 Section 5.2</a>
*/
public void setHeadersCharset(Charset headersCharset) {
Assert.notNull(headersCharset, "HeadersCharset must not be null");
this.headersCharset = headersCharset;
}
@Override
public List<MediaType> getReadableMediaTypes() {
return Collections.singletonList(MediaType.MULTIPART_FORM_DATA);
@@ -224,15 +214,15 @@ public class DefaultPartHttpMessageReader extends LoggingCodecSupport implements
message.getHeaders().getContentType() + "\""));
}
Flux<MultipartParser.Token> tokens = MultipartParser.parse(message.getBody(), boundary,
this.maxHeadersSize, this.headersCharset);
this.maxHeadersSize);
return PartGenerator.createParts(tokens, this.maxParts, this.maxInMemorySize, this.maxDiskUsagePerPart,
this.streaming, this.fileStorage.directory(), this.blockingOperationScheduler);
this.streaming, this.fileStorageDirectory, this.blockingOperationScheduler);
});
}
@Nullable
private byte[] boundary(HttpMessage message) {
private static byte[] boundary(HttpMessage message) {
MediaType contentType = message.getHeaders().getContentType();
if (contentType != null) {
String boundary = contentType.getParameter("boundary");
@@ -241,10 +231,22 @@ public class DefaultPartHttpMessageReader extends LoggingCodecSupport implements
if (len > 2 && boundary.charAt(0) == '"' && boundary.charAt(len - 1) == '"') {
boundary = boundary.substring(1, len - 1);
}
return boundary.getBytes(this.headersCharset);
return boundary.getBytes(StandardCharsets.ISO_8859_1);
}
}
return null;
}
@SuppressWarnings("BlockingMethodInNonBlockingContext")
private Mono<Path> defaultFileStorageDirectory() {
return Mono.fromCallable(() -> {
Path tempDirectory = Paths.get(System.getProperty("java.io.tmpdir"), IDENTIFIER);
if (!Files.exists(tempDirectory)) {
Files.createDirectory(tempDirectory);
}
return tempDirectory;
}).subscribeOn(this.blockingOperationScheduler);
}
}
@@ -1,128 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.codec.multipart;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
/**
* Represents a directory used to store parts larger than
* {@link DefaultPartHttpMessageReader#setMaxInMemorySize(int)}.
*
* @author Arjen Poutsma
* @since 5.3.7
*/
abstract class FileStorage {
private static final Log logger = LogFactory.getLog(FileStorage.class);
protected FileStorage() {
}
/**
* Get the mono of the directory to store files in.
*/
public abstract Mono<Path> directory();
/**
* Create a new {@code FileStorage} from a user-specified path. Creates the
* path if it does not exist.
*/
public static FileStorage fromPath(Path path) throws IOException {
if (!Files.exists(path)) {
Files.createDirectory(path);
}
return new PathFileStorage(path);
}
/**
* Create a new {@code FileStorage} based a on a temporary directory.
* @param scheduler scheduler to use for blocking operations
*/
public static FileStorage tempDirectory(Supplier<Scheduler> scheduler) {
return new TempFileStorage(scheduler);
}
private static final class PathFileStorage extends FileStorage {
private final Mono<Path> directory;
public PathFileStorage(Path directory) {
this.directory = Mono.just(directory);
}
@Override
public Mono<Path> directory() {
return this.directory;
}
}
private static final class TempFileStorage extends FileStorage {
private static final String IDENTIFIER = "spring-multipart-";
private final Supplier<Scheduler> scheduler;
private volatile Mono<Path> directory = tempDirectory();
public TempFileStorage(Supplier<Scheduler> scheduler) {
this.scheduler = scheduler;
}
@Override
public Mono<Path> directory() {
return this.directory
.flatMap(this::createNewDirectoryIfDeleted)
.subscribeOn(this.scheduler.get());
}
private Mono<Path> createNewDirectoryIfDeleted(Path directory) {
if (!Files.exists(directory)) {
// Some daemons remove temp directories. Let's create a new one.
Mono<Path> newDirectory = tempDirectory();
this.directory = newDirectory;
return newDirectory;
}
else {
return Mono.just(directory);
}
}
private static Mono<Path> tempDirectory() {
return Mono.fromCallable(() -> {
Path directory = Files.createTempDirectory(IDENTIFIER);
if (logger.isDebugEnabled()) {
logger.debug("Created temporary storage directory: " + directory);
}
return directory;
}).cache();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,7 +16,7 @@
package org.springframework.http.codec.multipart;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -69,14 +69,11 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
private final AtomicBoolean requestOutstanding = new AtomicBoolean();
private final Charset headersCharset;
private MultipartParser(FluxSink<Token> sink, byte[] boundary, int maxHeadersSize, Charset headersCharset) {
private MultipartParser(FluxSink<Token> sink, byte[] boundary, int maxHeadersSize) {
this.sink = sink;
this.boundary = boundary;
this.maxHeadersSize = maxHeadersSize;
this.headersCharset = headersCharset;
this.state = new AtomicReference<>(new PreambleState());
}
@@ -85,13 +82,11 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
* @param buffers the input buffers
* @param boundary the multipart boundary, as found in the {@code Content-Type} header
* @param maxHeadersSize the maximum buffered header size
* @param headersCharset the charset to use for decoding headers
* @return a stream of parsed tokens
*/
public static Flux<Token> parse(Flux<DataBuffer> buffers, byte[] boundary, int maxHeadersSize,
Charset headersCharset) {
public static Flux<Token> parse(Flux<DataBuffer> buffers, byte[] boundary, int maxHeadersSize) {
return Flux.create(sink -> {
MultipartParser parser = new MultipartParser(sink, boundary, maxHeadersSize, headersCharset);
MultipartParser parser = new MultipartParser(sink, boundary, maxHeadersSize);
sink.onCancel(parser::onSinkCancel);
sink.onRequest(n -> parser.requestBuffer());
buffers.subscribe(parser);
@@ -185,7 +180,7 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
/**
* Represents the output of {@link #parse(Flux, byte[], int, Charset)}.
* Represents the output of {@link #parse(Flux, byte[], int)}.
*/
public abstract static class Token {
@@ -377,6 +372,7 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
DataBufferUtils.release(buf);
emitHeaders(parseHeaders());
// TODO: no need to check result of changeState, no further statements
changeState(this, new BodyState(), bodyBuf);
}
else {
@@ -412,7 +408,7 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
}
DataBuffer joined = this.buffers.get(0).factory().join(this.buffers);
this.buffers.clear();
String string = joined.toString(MultipartParser.this.headersCharset);
String string = joined.toString(StandardCharsets.ISO_8859_1);
DataBufferUtils.release(joined);
String[] lines = string.split(HEADER_ENTRY_SEPARATOR);
HttpHeaders result = new HttpHeaders();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,6 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
@@ -54,7 +53,7 @@ import org.springframework.util.FastByteArrayOutputStream;
/**
* Subscribes to a token stream (i.e. the result of
* {@link MultipartParser#parse(Flux, byte[], int, Charset)}, and produces a flux of {@link Part} objects.
* {@link MultipartParser#parse(Flux, byte[], int)}, and produces a flux of {@link Part} objects.
*
* @author Arjen Poutsma
* @since 5.3
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 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,11 @@
package org.springframework.http.codec.multipart;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
@@ -80,16 +78,12 @@ import org.springframework.util.Assert;
*/
public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implements HttpMessageReader<Part> {
private static final String FILE_STORAGE_DIRECTORY_PREFIX = "synchronoss-file-upload-";
private int maxInMemorySize = 256 * 1024;
private long maxDiskUsagePerPart = -1;
private int maxParts = -1;
private Path fileStorageDirectory = createTempDirectory();
/**
* Configure the maximum amount of memory that is allowed to use per part.
@@ -150,22 +144,6 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem
return this.maxParts;
}
/**
* Set the directory used to store parts larger than
* {@link #setMaxInMemorySize(int) maxInMemorySize}. By default, a new
* temporary directory is created.
* @throws IOException if an I/O error occurs, or the parent directory
* does not exist
* @since 5.3.7
*/
public void setFileStorageDirectory(Path fileStorageDirectory) throws IOException {
Assert.notNull(fileStorageDirectory, "FileStorageDirectory must not be null");
if (!Files.exists(fileStorageDirectory)) {
Files.createDirectory(fileStorageDirectory);
}
this.fileStorageDirectory = fileStorageDirectory;
}
@Override
public List<MediaType> getReadableMediaTypes() {
@@ -189,7 +167,7 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem
@Override
public Flux<Part> read(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints) {
return Flux.create(new SynchronossPartGenerator(message, this.fileStorageDirectory))
return Flux.create(new SynchronossPartGenerator(message))
.doOnNext(part -> {
if (!Hints.isLoggingSuppressed(hints)) {
LogFormatUtils.traceDebug(logger, traceOn -> Hints.getLogPrefix(hints) + "Parsed " +
@@ -205,15 +183,6 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem
return Mono.error(new UnsupportedOperationException("Cannot read multipart request body into single Part"));
}
private static Path createTempDirectory() {
try {
return Files.createTempDirectory(FILE_STORAGE_DIRECTORY_PREFIX);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
/**
* Subscribe to the input stream and feed the Synchronoss parser. Then listen
@@ -225,17 +194,14 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem
private final LimitedPartBodyStreamStorageFactory storageFactory = new LimitedPartBodyStreamStorageFactory();
private final Path fileStorageDirectory;
@Nullable
private NioMultipartParserListener listener;
@Nullable
private NioMultipartParser parser;
public SynchronossPartGenerator(ReactiveHttpInputMessage inputMessage, Path fileStorageDirectory) {
public SynchronossPartGenerator(ReactiveHttpInputMessage inputMessage) {
this.inputMessage = inputMessage;
this.fileStorageDirectory = fileStorageDirectory;
}
@Override
@@ -252,7 +218,6 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem
this.parser = Multipart
.multipart(context)
.saveTemporaryFilesTo(this.fileStorageDirectory.toString())
.usePartBodyStreamStorageFactory(this.storageFactory)
.forNIO(this.listener);
@@ -68,10 +68,10 @@ public abstract class AbstractListenerReadPublisher<T> implements Publisher<T> {
@Nullable
private volatile Subscriber<? super T> subscriber;
private volatile boolean completionPending;
private volatile boolean completionBeforeDemand;
@Nullable
private volatile Throwable errorPending;
private volatile Throwable errorBeforeDemand;
private final String logPrefix;
@@ -186,7 +186,7 @@ public abstract class AbstractListenerReadPublisher<T> implements Publisher<T> {
*/
private boolean readAndPublish() throws IOException {
long r;
while ((r = this.demand) > 0 && (this.state.get() != State.COMPLETED)) {
while ((r = this.demand) > 0 && !this.state.get().equals(State.COMPLETED)) {
T data = read();
if (data != null) {
if (r != Long.MAX_VALUE) {
@@ -222,30 +222,27 @@ public abstract class AbstractListenerReadPublisher<T> implements Publisher<T> {
// Protect from infinite recursion in Undertow, where we can't check if data
// is available, so all we can do is to try to read.
// Generally, no need to check if we just came out of readAndPublish()...
if (oldState != State.READING) {
if (!oldState.equals(State.READING)) {
checkOnDataAvailable();
}
}
}
private boolean handlePendingCompletionOrError() {
private void handleCompletionOrErrorBeforeDemand() {
State state = this.state.get();
if (state == State.DEMAND || state == State.NO_DEMAND) {
if (this.completionPending) {
rsReadLogger.trace(getLogPrefix() + "Processing pending completion");
if (!state.equals(State.UNSUBSCRIBED) && !state.equals(State.SUBSCRIBING)) {
if (this.completionBeforeDemand) {
rsReadLogger.trace(getLogPrefix() + "Completed before demand");
this.state.get().onAllDataRead(this);
return true;
}
Throwable ex = this.errorPending;
Throwable ex = this.errorBeforeDemand;
if (ex != null) {
if (rsReadLogger.isTraceEnabled()) {
rsReadLogger.trace(getLogPrefix() + "Processing pending completion with error: " + ex);
rsReadLogger.trace(getLogPrefix() + "Completed with error before demand: " + ex);
}
this.state.get().onError(this, ex);
return true;
}
}
return false;
}
private Subscription createSubscription() {
@@ -308,7 +305,7 @@ public abstract class AbstractListenerReadPublisher<T> implements Publisher<T> {
publisher.subscriber = subscriber;
subscriber.onSubscribe(subscription);
publisher.changeState(SUBSCRIBING, NO_DEMAND);
publisher.handlePendingCompletionOrError();
publisher.handleCompletionOrErrorBeforeDemand();
}
else {
throw new IllegalStateException("Failed to transition to SUBSCRIBING, " +
@@ -318,14 +315,14 @@ public abstract class AbstractListenerReadPublisher<T> implements Publisher<T> {
@Override
<T> void onAllDataRead(AbstractListenerReadPublisher<T> publisher) {
publisher.completionPending = true;
publisher.handlePendingCompletionOrError();
publisher.completionBeforeDemand = true;
publisher.handleCompletionOrErrorBeforeDemand();
}
@Override
<T> void onError(AbstractListenerReadPublisher<T> publisher, Throwable ex) {
publisher.errorPending = ex;
publisher.handlePendingCompletionOrError();
publisher.errorBeforeDemand = ex;
publisher.handleCompletionOrErrorBeforeDemand();
}
},
@@ -344,14 +341,14 @@ public abstract class AbstractListenerReadPublisher<T> implements Publisher<T> {
@Override
<T> void onAllDataRead(AbstractListenerReadPublisher<T> publisher) {
publisher.completionPending = true;
publisher.handlePendingCompletionOrError();
publisher.completionBeforeDemand = true;
publisher.handleCompletionOrErrorBeforeDemand();
}
@Override
<T> void onError(AbstractListenerReadPublisher<T> publisher, Throwable ex) {
publisher.errorPending = ex;
publisher.handlePendingCompletionOrError();
publisher.errorBeforeDemand = ex;
publisher.handleCompletionOrErrorBeforeDemand();
}
},
@@ -382,17 +379,14 @@ public abstract class AbstractListenerReadPublisher<T> implements Publisher<T> {
boolean demandAvailable = publisher.readAndPublish();
if (demandAvailable) {
publisher.changeToDemandState(READING);
publisher.handlePendingCompletionOrError();
}
else {
publisher.readingPaused();
if (publisher.changeState(READING, NO_DEMAND)) {
if (!publisher.handlePendingCompletionOrError()) {
// Demand may have arrived since readAndPublish returned
long r = publisher.demand;
if (r > 0) {
publisher.changeToDemandState(NO_DEMAND);
}
// Demand may have arrived since readAndPublish returned
long r = publisher.demand;
if (r > 0) {
publisher.changeToDemandState(NO_DEMAND);
}
}
}
@@ -414,18 +408,6 @@ public abstract class AbstractListenerReadPublisher<T> implements Publisher<T> {
publisher.changeToDemandState(NO_DEMAND);
}
}
@Override
<T> void onAllDataRead(AbstractListenerReadPublisher<T> publisher) {
publisher.completionPending = true;
publisher.handlePendingCompletionOrError();
}
@Override
<T> void onError(AbstractListenerReadPublisher<T> publisher, Throwable ex) {
publisher.errorPending = ex;
publisher.handlePendingCompletionOrError();
}
},
COMPLETED {

Some files were not shown because too many files have changed in this diff Show More