Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Buildmaster 83c6d10095 Release v5.3.6 2021-04-13 11:08:55 +00:00
253 changed files with 2712 additions and 4676 deletions
+39 -37
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.10' apply false
id 'org.jetbrains.kotlin.jvm' version '1.4.32' 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.10" 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.32" apply false
}
ext {
@@ -27,16 +26,15 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.3"
mavenBom "io.netty:netty-bom:4.1.65.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.7"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR10"
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.2"
mavenBom "io.netty:netty-bom:4.1.63.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.6"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR9"
mavenBom "io.rsocket:rsocket-bom:1.1.0"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.41.v20210516"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.10"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.0"
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.1"
mavenBom "org.junit:junit-bom:5.7.2"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.39.v20210325"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.32"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.3"
mavenBom "org.junit:junit-bom:5.7.1"
}
dependencies {
dependencySet(group: 'org.apache.logging.log4j', version: '2.14.1') {
@@ -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.13"
dependency "io.reactivex.rxjava3:rxjava:3.0.12"
dependency "io.projectreactor.tools:blockhound:1.0.4.RELEASE"
dependency "com.caucho:hessian:4.0.63"
dependency "com.fasterxml:aalto-xml:1.3.0"
dependency("com.fasterxml.woodstox:woodstox-core:6.2.6") {
dependency "com.fasterxml:aalto-xml:1.2.2"
dependency("com.fasterxml.woodstox:woodstox-core:6.2.4") {
exclude group: "stax", name: "stax-api"
}
dependency "com.google.code.gson:gson:2.8.7"
dependency "com.google.protobuf:protobuf-java-util:3.17.2"
dependency "com.google.code.gson:gson:2.8.6"
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.17") {
dependency("com.thoughtworks.xstream:xstream:1.4.15") {
exclude group: "xpp3", name: "xpp3_min"
exclude group: "xmlpull", name: "xmlpull"
}
@@ -92,15 +90,19 @@ 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"
dependency "net.sf.jopt-simple:jopt-simple:5.0.4"
dependencySet(group: 'org.apache.activemq', version: '5.16.2') {
dependencySet(group: 'org.apache.activemq', version: '5.16.1') {
entry 'activemq-broker'
entry('activemq-kahadb-store') {
exclude group: "org.springframework", name: "spring-context"
@@ -116,13 +118,13 @@ 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.hsqldb:hsqldb:2.5.2"
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.32.Final"
dependency "org.hibernate:hibernate-core:5.4.30.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"
@@ -138,7 +140,7 @@ configure(allprojects) { project ->
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.8.Final') {
dependencySet(group: 'io.undertow', version: '2.2.7.Final') {
entry 'undertow-core'
entry('undertow-websockets-jsr') {
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
@@ -159,11 +161,11 @@ configure(allprojects) { project ->
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency 'org.apache.httpcomponents.client5:httpclient5:5.1'
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.1.1'
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.8"
dependency 'org.apache.httpcomponents.client5:httpclient5:5.0.3'
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.0.3'
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.6"
dependency "org.jruby:jruby:9.2.17.0"
dependency "org.jruby:jruby:9.2.16.0"
dependency "org.python:jython-standalone:2.7.1"
dependency "org.mozilla:rhino:1.7.11"
@@ -196,7 +198,7 @@ configure(allprojects) { project ->
exclude group: "org.hamcrest", name: "hamcrest-core"
}
}
dependencySet(group: 'org.mockito', version: '3.11.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.50.0") {
dependency("net.sourceforge.htmlunit:htmlunit:2.48.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.50.0") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.48.0") {
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", "-Xopt-in=kotlin.RequiresOptIn"]
freeCompilerArgs = ["-Xjsr305=strict"]
allWarningsAsErrors = true
}
}
@@ -336,7 +338,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "8.43"
toolVersion = "8.41"
configDirectory.set(rootProject.file("src/checkstyle"))
}
@@ -375,10 +377,10 @@ configure([rootProject] + javaProjects) { project ->
"https://fasterxml.github.io/jackson-core/javadoc/2.10/",
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
"https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/",
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/",
"https://projectreactor.io/docs/test/release/api/",
"https://junit.org/junit4/javadoc/4.13.2/",
"https://junit.org/junit5/docs/5.7.2/api/"
"https://junit.org/junit5/docs/5.7.1/api/"
] as String[]
}
+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"
+8 -56
View File
@@ -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:
@@ -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,4 +1,4 @@
version=5.3.8
version=5.3.6
org.gradle.jvmargs=-Xmx1536M
org.gradle.caching=true
org.gradle.parallel=true
+1 -2
View File
@@ -143,8 +143,7 @@ asciidoctorj {
'highlightjs-theme': 'googlecode',
stylesdir: 'css/',
stylesheet: 'stylesheet.css',
'spring-version': project.version,
'spring-framework-main-code': 'https://github.com/spring-projects/spring-framework/tree/main'
'spring-version': project.version
])
}
+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'
}
+15 -73
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,19 @@
* /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()
}
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') && project.mainToolchain) {
def mainLanguageVersion = JavaLanguageVersion.of(project.mainToolchain.toString())
java {
toolchain {
languageVersion = mainToolchainLanguageVersion()
languageVersion = mainLanguageVersion
}
}
}
@@ -70,8 +46,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') && project.testToolchain) {
def testLanguageVersion = JavaLanguageVersion.of(project.testToolchain.toString());
tasks.withType(JavaCompile).matching { it.name.contains("Test") }.configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = testLanguageVersion
@@ -87,17 +63,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') && project.mainToolchain) {
def mainLanguageVersion = JavaLanguageVersion.of(project.mainToolchain.toString());
def compiler = javaToolchains.compilerFor {
languageVersion = mainLanguageVersion
}
@@ -130,9 +106,9 @@ pluginManager.withPlugin("kotlin") {
}
}
}
if (testToolchainConfigured()) {
def testLanguageVersion = testToolchainLanguageVersion()
if (project.hasProperty('testToolchain') && project.testToolchain) {
def testLanguageVersion = JavaLanguageVersion.of(project.testToolchain.toString());
def compiler = javaToolchains.compilerFor {
languageVersion = testLanguageVersion
}
@@ -145,38 +121,4 @@ 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()
}
}
}
}
// 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
}
}
}
+6
View File
@@ -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-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.
@@ -84,7 +84,7 @@ import org.springframework.lang.Nullable;
* (only applicable when running in a web application context)
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
* <li>InitializingBean's {@code afterPropertiesSet}
* <li>a custom {@code init-method} definition
* <li>a custom init-method definition
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
* </ol>
*
@@ -92,7 +92,7 @@ import org.springframework.lang.Nullable;
* <ol>
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
* <li>DisposableBean's {@code destroy}
* <li>a custom {@code destroy-method} definition
* <li>a custom destroy-method definition
* </ol>
*
* @author Rod Johnson
@@ -102,8 +102,6 @@ import org.springframework.lang.Nullable;
* @see BeanNameAware#setBeanName
* @see BeanClassLoaderAware#setBeanClassLoader
* @see BeanFactoryAware#setBeanFactory
* @see org.springframework.context.EnvironmentAware#setEnvironment
* @see org.springframework.context.EmbeddedValueResolverAware#setEmbeddedValueResolver
* @see org.springframework.context.ResourceLoaderAware#setResourceLoader
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
* @see org.springframework.context.MessageSourceAware#setMessageSource
@@ -113,7 +111,6 @@ import org.springframework.lang.Nullable;
* @see InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
* @see DisposableBean#destroy
* @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
*/
@@ -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.
@@ -35,7 +35,6 @@ import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -245,10 +244,8 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
return (bean.equals(null) ? null : bean);
}
else {
// Find target bean matching the (potentially generic) method return type
ResolvableType genericReturnType = ResolvableType.forMethodReturnType(method);
return (argsToUse != null ? this.owner.getBeanProvider(genericReturnType).getObject(argsToUse) :
this.owner.getBeanProvider(genericReturnType).getObject());
return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
this.owner.getBean(method.getReturnType()));
}
}
}
@@ -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.
@@ -19,25 +19,17 @@ package org.springframework.beans.factory.support;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
* Represents an override of a method that looks up an object in the same IoC context,
* either by bean name or by bean type (based on the declared method return type).
* Represents an override of a method that looks up an object in the same IoC context.
*
* <p>Methods eligible for lookup override may declare arguments in which case the
* given arguments are passed to the bean retrieval operation.
* <p>Methods eligible for lookup override must not have arguments.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 1.1
* @see org.springframework.beans.factory.BeanFactory#getBean(String)
* @see org.springframework.beans.factory.BeanFactory#getBean(Class)
* @see org.springframework.beans.factory.BeanFactory#getBean(String, Object...)
* @see org.springframework.beans.factory.BeanFactory#getBean(Class, Object...)
* @see org.springframework.beans.factory.BeanFactory#getBeanProvider(ResolvableType)
*/
public class LookupOverride extends MethodOverride {
@@ -51,8 +43,8 @@ public class LookupOverride extends MethodOverride {
/**
* Construct a new LookupOverride.
* @param methodName the name of the method to override
* @param beanName the name of the bean in the current {@code BeanFactory} that the
* overridden method should return (may be {@code null} for type-based bean retrieval)
* @param beanName the name of the bean in the current {@code BeanFactory}
* that the overridden method should return (may be {@code null})
*/
public LookupOverride(String methodName, @Nullable String beanName) {
super(methodName);
@@ -61,9 +53,9 @@ public class LookupOverride extends MethodOverride {
/**
* Construct a new LookupOverride.
* @param method the method declaration to override
* @param beanName the name of the bean in the current {@code BeanFactory} that the
* overridden method should return (may be {@code null} for type-based bean retrieval)
* @param method the method to override
* @param beanName the name of the bean in the current {@code BeanFactory}
* that the overridden method should return (may be {@code null})
*/
public LookupOverride(Method method, @Nullable String beanName) {
super(method.getName());
@@ -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.
@@ -19,8 +19,9 @@ package org.springframework.beans.factory.support;
import java.lang.reflect.Method;
/**
* Interface to be implemented by classes that can reimplement any method on an
* IoC-managed object: the <b>Method Injection</b> form of Dependency Injection.
* Interface to be implemented by classes that can reimplement any method
* on an IoC-managed object: the <b>Method Injection</b> form of
* Dependency Injection.
*
* <p>Such methods may be (but need not be) abstract, in which case the
* container will create a concrete subclass to instantiate.
@@ -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.
@@ -25,7 +25,7 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Extension of {@link MethodOverride} that represents an arbitrary
* Extension of MethodOverride that represents an arbitrary
* override of a method by the IoC container.
*
* <p>Any non-final method can be overridden, irrespective of its
@@ -45,7 +45,7 @@ public class ReplaceOverride extends MethodOverride {
/**
* Construct a new ReplaceOverride.
* @param methodName the name of the method to override
* @param methodReplacerBeanName the bean name of the {@link MethodReplacer}
* @param methodReplacerBeanName the bean name of the MethodReplacer
*/
public ReplaceOverride(String methodName, String methodReplacerBeanName) {
super(methodName);
@@ -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
@@ -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);
@@ -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.
@@ -18,14 +18,14 @@ package org.springframework.beans;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -36,21 +36,23 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Beams
* @since 08.03.2004
*/
class ConcurrentBeanWrapperTests {
public class ConcurrentBeanWrapperTests {
private final Log logger = LogFactory.getLog(getClass());
private final Set<TestRun> set = ConcurrentHashMap.newKeySet();
private Set<TestRun> set = Collections.synchronizedSet(new HashSet<TestRun>());
private Throwable ex = null;
@RepeatedTest(100)
void testSingleThread() {
performSet();
@Test
public void testSingleThread() {
for (int i = 0; i < 100; i++) {
performSet();
}
}
@Test
void testConcurrent() {
public void testConcurrent() {
for (int i = 0; i < 10; i++) {
TestRun run = new TestRun(this);
set.add(run);
@@ -80,7 +82,7 @@ class ConcurrentBeanWrapperTests {
Properties p = (Properties) System.getProperties().clone();
assertThat(p).as("The System properties must not be empty").isNotEmpty();
assertThat(p.size() != 0).as("The System properties must not be empty").isTrue();
for (Iterator<?> i = p.entrySet().iterator(); i.hasNext();) {
i.next();
@@ -109,7 +111,7 @@ class ConcurrentBeanWrapperTests {
private ConcurrentBeanWrapperTests test;
TestRun(ConcurrentBeanWrapperTests test) {
public TestRun(ConcurrentBeanWrapperTests test) {
this.test = test;
}
@@ -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.
@@ -121,18 +121,6 @@ public class LookupAnnotationTests {
assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
}
@Test
public void testWithGenericBean() {
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class));
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
assertThat(bean).isNotNull();
assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
}
public static abstract class AbstractBean {
@@ -159,26 +147,4 @@ public class LookupAnnotationTests {
AbstractBean abstractBean;
}
public static class NumberStore<T extends Number> {
}
public static class DoubleStore extends NumberStore<Double> {
}
public static class FloatStore extends NumberStore<Float> {
}
public static abstract class NumberBean {
@Lookup
public abstract NumberStore<Double> getDoubleStore();
@Lookup
public abstract NumberStore<Float> getFloatStore();
}
}
@@ -141,7 +141,6 @@ class YamlProcessorTests {
}
@Test
@SuppressWarnings("unchecked")
void standardTypesSupportedByDefault() throws Exception {
setYaml("value: !!set\n ? first\n ? second");
this.processor.process((properties, map) -> {
@@ -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.
@@ -36,7 +36,7 @@ public class LookupMethodTests {
@BeforeEach
public void setup() {
public void setUp() {
beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("lookupMethodTests.xml", getClass()));
@@ -83,8 +83,8 @@ public class LookupMethodTests {
public void testWithThreeArgsShouldFail() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
assertThat(bean).isNotNull();
assertThatExceptionOfType(AbstractMethodError.class).as("does not have a three arg constructor")
.isThrownBy(() -> bean.getThreeArguments("name", 1, 2));
assertThatExceptionOfType(AbstractMethodError.class).as("does not have a three arg constructor").isThrownBy(() ->
bean.getThreeArguments("name", 1, 2));
}
@Test
@@ -97,21 +97,6 @@ public class LookupMethodTests {
assertThat(expected.isJedi()).isTrue();
}
@Test
public void testWithGenericBean() {
RootBeanDefinition bd = new RootBeanDefinition(NumberBean.class);
bd.getMethodOverrides().addOverride(new LookupOverride("getDoubleStore", null));
bd.getMethodOverrides().addOverride(new LookupOverride("getFloatStore", null));
beanFactory.registerBeanDefinition("numberBean", bd);
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
assertThat(bean).isNotNull();
assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
}
public static abstract class AbstractBean {
@@ -126,24 +111,4 @@ public class LookupMethodTests {
public abstract TestBean getThreeArguments(String name, int age, int anotherArg);
}
public static class NumberStore<T extends Number> {
}
public static class DoubleStore extends NumberStore<Double> {
}
public static class FloatStore extends NumberStore<Float> {
}
public static abstract class NumberBean {
public abstract NumberStore<Double> getDoubleStore();
public abstract NumberStore<Float> getFloatStore();
}
}
@@ -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;
@@ -36,7 +37,7 @@ import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
/**
* Annotation {@link Processor} that writes a {@link CandidateComponentsMetadata}
* Annotation {@link Processor} that writes {@link CandidateComponentsMetadata}
* file for spring components.
*
* @author Stephane Nicoll
@@ -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.
@@ -26,7 +26,7 @@ import javax.lang.model.element.ElementKind;
/**
* A {@link StereotypesProvider} implementation that extracts the stereotypes
* flagged by the {@value #INDEXED_ANNOTATION} annotation. This implementation
* flagged by the {@value INDEXED_ANNOTATION} annotation. This implementation
* honors stereotypes defined this way on meta-annotations.
*
* @author Stephane Nicoll
@@ -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<>();
@@ -24,7 +24,7 @@ import javax.lang.model.element.ElementKind;
/**
* A {@link StereotypesProvider} implementation that provides the
* {@value #STEREOTYPE} stereotype for each package-info.
* {@value STEREOTYPE} stereotype for each package-info.
*
* @author Stephane Nicoll
* @since 5.0
@@ -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.
@@ -24,8 +24,8 @@ import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
/**
* A {@link StereotypesProvider} that extracts a stereotype for each
* {@code javax.*} annotation <i>present</i> on a class or interface.
* A {@link StereotypesProvider} that extract a stereotype for each
* {@code javax.*} annotation placed on a class or interface.
*
* @author Stephane Nicoll
* @since 5.0
@@ -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.
@@ -22,7 +22,7 @@ import javax.lang.model.element.Element;
/**
* Provide the list of stereotypes that match an {@link Element}.
* <p>If an element has one or more stereotypes, it is referenced in the index
* If an element has one more stereotypes, it is referenced in the index
* of candidate components and each stereotype can be queried individually.
*
* @author Stephane Nicoll
@@ -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-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.
@@ -16,7 +16,6 @@
package org.springframework.context;
import java.time.Clock;
import java.util.EventObject;
/**
@@ -38,37 +37,18 @@ public abstract class ApplicationEvent extends EventObject {
/**
* Create a new {@code ApplicationEvent} with its {@link #getTimestamp() timestamp}
* set to {@link System#currentTimeMillis()}.
* Create a new {@code ApplicationEvent}.
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
* @see #ApplicationEvent(Object, Clock)
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Create a new {@code ApplicationEvent} with its {@link #getTimestamp() timestamp}
* set to the value returned by {@link Clock#millis()} in the provided {@link Clock}.
* <p>This constructor is typically used in testing scenarios.
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
* @param clock a clock which will provide the timestamp
* @since 5.3.8
* @see #ApplicationEvent(Object)
*/
public ApplicationEvent(Object source, Clock clock) {
super(source);
this.timestamp = clock.millis();
}
/**
* Return the time in milliseconds when the event occurred.
* @see #ApplicationEvent(Object)
* @see #ApplicationEvent(Object, Clock)
* Return the system time in milliseconds when the event occurred.
*/
public final long getTimestamp() {
return this.timestamp;
@@ -84,7 +84,6 @@ import org.springframework.core.annotation.AliasFor;
* @author Sam Brannen
* @since 4.2
* @see EventListenerMethodProcessor
* @see org.springframework.transaction.event.TransactionalEventListener
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@@ -134,7 +133,7 @@ public @interface EventListener {
* An optional identifier for the listener, defaulting to the fully-qualified
* signature of the declaring method (e.g. "mypackage.MyClass.myMethod()").
* @since 5.3.5
* @see SmartApplicationListener#getListenerId()
* @see org.springframework.context.ApplicationListener#getListenerId()
* @see ApplicationEventMulticaster#removeApplicationListeners(Predicate)
*/
String id() default "";
@@ -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;
@@ -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.
@@ -192,11 +192,6 @@ final class BitsCronField extends CronField {
while (current != next && count++ < CronExpression.MAX_ATTEMPTS) {
temporal = type().elapseUntil(temporal, next);
current = type().get(temporal);
next = nextSetBit(current);
if (next == -1) {
temporal = type().rollForward(temporal);
next = nextSetBit(0);
}
}
if (count >= CronExpression.MAX_ATTEMPTS) {
return null;
@@ -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.
@@ -202,25 +202,6 @@ public final class CronExpression {
}
}
/**
* Determine whether the given string represents a valid cron expression.
* @param expression the expression to evaluate
* @return {@code true} if the given expression is a valid cron expression
* @since 5.3.8
*/
public static boolean isValidExpression(@Nullable String expression) {
if (expression == null) {
return false;
}
try {
parse(expression);
return true;
}
catch (IllegalArgumentException ex) {
return false;
}
}
private static String resolveMacros(String expression) {
expression = expression.trim();
@@ -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,16 @@ 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);
T result = this.field.getBaseUnit().addTo(temporal, goal - current);
current = get(result);
if (current > goal) { // can occur due to daylight saving, see gh-26744
result = this.field.getBaseUnit().addTo(result, goal - current);
}
return result;
}
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-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.
@@ -18,7 +18,6 @@ package org.springframework.validation.support;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.ui.ConcurrentModel;
import org.springframework.validation.BindingResult;
@@ -37,19 +36,17 @@ import org.springframework.validation.BindingResult;
* @author Rossen Stoyanchev
* @since 5.0
* @see BindingResult
* @see BindingAwareModelMap
*/
@SuppressWarnings("serial")
public class BindingAwareConcurrentModel extends ConcurrentModel {
@Override
@Nullable
public Object put(String key, @Nullable Object value) {
public Object put(String key, Object value) {
removeBindingResultIfNecessary(key, value);
return super.put(key, value);
}
private void removeBindingResultIfNecessary(String key, @Nullable Object value) {
private void removeBindingResultIfNecessary(String key, Object value) {
if (!key.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
String resultKey = BindingResult.MODEL_KEY_PREFIX + key;
BindingResult result = (BindingResult) get(resultKey);
@@ -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.
@@ -18,7 +18,6 @@ package org.springframework.validation.support;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.validation.BindingResult;
@@ -40,7 +39,7 @@ import org.springframework.validation.BindingResult;
public class BindingAwareModelMap extends ExtendedModelMap {
@Override
public Object put(String key, @Nullable Object value) {
public Object put(String key, Object value) {
removeBindingResultIfNecessary(key, value);
return super.put(key, value);
}
@@ -51,7 +50,7 @@ public class BindingAwareModelMap extends ExtendedModelMap {
super.putAll(map);
}
private void removeBindingResultIfNecessary(Object key, @Nullable Object value) {
private void removeBindingResultIfNecessary(Object key, Object value) {
if (key instanceof String) {
String attributeName = (String) key;
if (!attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
@@ -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");
}
}
@@ -339,11 +339,10 @@ class DateTimeFormattingTests {
.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")
"@org.springframework.format.annotation.DateTimeFormat",
"iso=DATE", "fallbackPatterns=[]")
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
.hasMessageStartingWith("Text '2009-31-10'")
.hasCauseInstanceOf(DateTimeException.class).getCause()
@@ -51,16 +51,6 @@ class CronExpressionTests {
}
};
@Test
public void isValidExpression() {
assertThat(CronExpression.isValidExpression(null)).isFalse();
assertThat(CronExpression.isValidExpression("")).isFalse();
assertThat(CronExpression.isValidExpression("*")).isFalse();
assertThat(CronExpression.isValidExpression("* * * * *")).isFalse();
assertThat(CronExpression.isValidExpression("* * * * * * *")).isFalse();
assertThat(CronExpression.isValidExpression("* * * * * *")).isTrue();
}
@Test
void matchAll() {
@@ -507,29 +497,6 @@ class CronExpressionTests {
assertThat(actual.getDayOfMonth()).isEqualTo(13);
}
@Test
public void everyTenDays() {
CronExpression cronExpression = CronExpression.parse("0 15 12 */10 1-8 5");
LocalDateTime last = LocalDateTime.parse("2021-04-30T12:14:59");
LocalDateTime expected = LocalDateTime.parse("2021-05-21T12:15");
LocalDateTime actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.parse("2021-06-11T12:15");
actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.parse("2022-01-21T12:15");
actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
}
@Test
void yearly() {
CronExpression expression = CronExpression.parse("@yearly");
@@ -1309,14 +1276,6 @@ class CronExpressionTests {
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) {
@@ -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,7 +17,10 @@
@file:JvmName("CoroutinesUtils")
package org.springframework.core
import kotlinx.coroutines.*
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.reactive.awaitSingleOrNull
import kotlinx.coroutines.reactor.asFlux
@@ -45,8 +48,6 @@ internal fun <T: Any> deferredToMono(source: Deferred<T>) =
* @author Sebastien Deleuze
* @since 5.2
*/
@Suppress("DEPRECATION")
@OptIn(DelicateCoroutinesApi::class)
internal fun <T: Any> monoToDeferred(source: Mono<T>) =
GlobalScope.async(Dispatchers.Unconfined) { source.awaitSingleOrNull() }
@@ -88,9 +88,6 @@ public class ClassReader {
*/
static final int EXPAND_ASM_INSNS = 256;
/** The maximum size of array to allocate. */
private static final int MAX_BUFFER_SIZE = 1024 * 1024;
/** The size of the temporary byte array used to read class input streams chunk by chunk. */
private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
@@ -313,19 +310,13 @@ public class ClassReader {
if (inputStream == null) {
throw new IOException("Class not found");
}
int bufferSize = calculateBufferSize(inputStream);
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
byte[] data = new byte[bufferSize];
byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE];
int bytesRead;
int readCount = 0;
while ((bytesRead = inputStream.read(data, 0, bufferSize)) != -1) {
while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
outputStream.write(data, 0, bytesRead);
readCount++;
}
outputStream.flush();
if (readCount == 1) {
return data;
}
return outputStream.toByteArray();
} finally {
if (close) {
@@ -334,20 +325,6 @@ public class ClassReader {
}
}
private static int calculateBufferSize(final InputStream inputStream) throws IOException {
int expectedLength = inputStream.available();
/*
* Some implementations can return 0 while holding available data
* (e.g. new FileInputStream("/proc/a_file"))
* Also in some pathological cases a very small number might be returned,
* and in this case we use default size
*/
if (expectedLength < 256) {
return INPUT_STREAM_DATA_CHUNK_SIZE;
}
return Math.min(expectedLength, MAX_BUFFER_SIZE);
}
// -----------------------------------------------------------------------------------------------
// Accessors
// -----------------------------------------------------------------------------------------------
@@ -3479,6 +3456,7 @@ public class ClassReader {
private int[] readBootstrapMethodsAttribute(final int maxStringLength) {
char[] charBuffer = new char[maxStringLength];
int currentAttributeOffset = getFirstAttributeOffset();
int[] currentBootstrapMethodOffsets = null;
for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
// Read the attribute_info's attribute_name and attribute_length fields.
String attributeName = readUTF8(currentAttributeOffset, charBuffer);
@@ -3486,17 +3464,17 @@ public class ClassReader {
currentAttributeOffset += 6;
if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
// Read the num_bootstrap_methods field and create an array of this size.
int[] result = new int[readUnsignedShort(currentAttributeOffset)];
currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)];
// Compute and store the offset of each 'bootstrap_methods' array field entry.
int currentBootstrapMethodOffset = currentAttributeOffset + 2;
for (int j = 0; j < result.length; ++j) {
result[j] = currentBootstrapMethodOffset;
for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) {
currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset;
// Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each),
// as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2).
currentBootstrapMethodOffset +=
4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2;
}
return result;
return currentBootstrapMethodOffsets;
}
currentAttributeOffset += attributeLength;
}
@@ -79,7 +79,7 @@ public class ClassWriter extends ClassVisitor {
/**
* The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific
* access flags, such as {@link Opcodes#ACC_DEPRECATED} or {@link Opcodes#ACC_RECORD}, which are
* access flags, such as {@link Opcodes#ACC_DEPRECATED} or {}@link Opcodes#ACC_RECORD}, which are
* removed when generating the ClassFile structure.
*/
private int accessFlags;
@@ -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.
@@ -71,7 +71,7 @@ public abstract class DataBufferUtils {
//---------------------------------------------------------------------
/**
* Obtain an {@link InputStream} from the given supplier, and read it into a
* Obtain a {@link InputStream} from the given supplier, and read it into a
* {@code Flux} of {@code DataBuffer}s. Closes the input stream when the
* Flux is terminated.
* @param inputStreamSupplier the supplier for the input stream to read from
@@ -125,7 +125,7 @@ public abstract class DataBufferUtils {
}
/**
* Obtain an {@code AsynchronousFileChannel} from the given supplier, and
* Obtain a {@code AsynchronousFileChannel} from the given supplier, and
* read it into a {@code Flux} of {@code DataBuffer}s, starting at the given
* position. Closes the channel when the Flux is terminated.
* @param channelSupplier the supplier for the channel to read from
@@ -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.
@@ -29,16 +29,16 @@ import java.util.function.Supplier;
*/
class DefaultApplicationStartup implements ApplicationStartup {
private static final DefaultStartupStep DEFAULT_STARTUP_STEP = new DefaultStartupStep();
@Override
public DefaultStartupStep start(String name) {
return DEFAULT_STARTUP_STEP;
return new DefaultStartupStep();
}
static class DefaultStartupStep implements StartupStep {
boolean recorded = false;
private final DefaultTags TAGS = new DefaultTags();
@Override
@@ -63,17 +63,23 @@ class DefaultApplicationStartup implements ApplicationStartup {
@Override
public StartupStep tag(String key, String value) {
if (this.recorded) {
throw new IllegalArgumentException();
}
return this;
}
@Override
public StartupStep tag(String key, Supplier<String> value) {
if (this.recorded) {
throw new IllegalArgumentException();
}
return this;
}
@Override
public void end() {
this.recorded = 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.
@@ -16,9 +16,8 @@
package org.springframework.core.metrics.jfr;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.core.metrics.StartupStep;
@@ -38,23 +37,24 @@ import org.springframework.core.metrics.StartupStep;
*/
public class FlightRecorderApplicationStartup implements ApplicationStartup {
private final AtomicLong currentSequenceId = new AtomicLong(0);
private long currentSequenceId;
private final Deque<Long> currentSteps;
public FlightRecorderApplicationStartup() {
this.currentSteps = new ConcurrentLinkedDeque<>();
this.currentSteps.offerFirst(this.currentSequenceId.get());
this.currentSequenceId = 0;
this.currentSteps = new ArrayDeque<>();
this.currentSteps.offerFirst(0L);
}
@Override
public StartupStep start(String name) {
long sequenceId = this.currentSequenceId.incrementAndGet();
this.currentSteps.offerFirst(sequenceId);
return new FlightRecorderStartupStep(sequenceId, name,
this.currentSteps.getFirst(), committedStep -> this.currentSteps.removeFirstOccurrence(sequenceId));
FlightRecorderStartupStep step = new FlightRecorderStartupStep(++this.currentSequenceId, name,
this.currentSteps.getFirst(), committedStep -> this.currentSteps.removeFirst());
this.currentSteps.offerFirst(this.currentSequenceId);
return step;
}
}
@@ -88,13 +88,13 @@ public abstract class ClassUtils {
* Map with primitive wrapper type as key and corresponding primitive
* type as value, for example: Integer.class -> int.class.
*/
private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new IdentityHashMap<>(9);
private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new IdentityHashMap<>(8);
/**
* Map with primitive type as key and corresponding wrapper
* type as value, for example: int.class -> Integer.class.
*/
private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap = new IdentityHashMap<>(9);
private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap = new IdentityHashMap<>(8);
/**
* Map with primitive type name as key and corresponding primitive
@@ -1322,7 +1322,7 @@ public abstract class ClassUtils {
* Note that, despite being synthetic, bridge methods ({@link Method#isBridge()}) are considered
* as user-level methods since they are eventually pointing to a user-declared generic method.
* @param method the method to check
* @return {@code true} if the method can be considered as user-declared; {@code false} otherwise
* @return {@code true} if the method can be considered as user-declared; [@code false} otherwise
*/
public static boolean isUserLevelMethod(Method method) {
Assert.notNull(method, "Method must not be null");
@@ -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
@@ -566,7 +566,7 @@ public abstract class StringUtils {
char[] chars = str.toCharArray();
chars[0] = updatedChar;
return new String(chars);
return new String(chars, 0, chars.length);
}
/**
@@ -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-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,18 +21,13 @@ import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit tests for {@link SimpleAliasRegistry}.
*
* @author Juergen Hoeller
* @author Nha Vuong
* @author Sam Brannen
*/
class SimpleAliasRegistryTests {
private final SimpleAliasRegistry registry = new SimpleAliasRegistry();
@Test
void aliasChaining() {
SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("test", "testAlias");
registry.registerAlias("testAlias", "testAlias2");
registry.registerAlias("testAlias2", "testAlias3");
@@ -47,6 +42,7 @@ class SimpleAliasRegistryTests {
@Test // SPR-17191
void aliasChainingWithMultipleAliases() {
SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("name", "alias_a");
registry.registerAlias("name", "alias_b");
assertThat(registry.hasAlias("name", "alias_a")).isTrue();
@@ -64,35 +60,4 @@ class SimpleAliasRegistryTests {
assertThat(registry.hasAlias("real_name", "alias_c")).isTrue();
}
@Test
void removeAlias() {
registry.registerAlias("real_name", "nickname");
assertThat(registry.hasAlias("real_name", "nickname")).isTrue();
registry.removeAlias("nickname");
assertThat(registry.hasAlias("real_name", "nickname")).isFalse();
}
@Test
void isAlias() {
registry.registerAlias("real_name", "nickname");
assertThat(registry.isAlias("nickname")).isTrue();
assertThat(registry.isAlias("real_name")).isFalse();
assertThat(registry.isAlias("fake")).isFalse();
}
@Test
void getAliases() {
registry.registerAlias("test", "testAlias1");
assertThat(registry.getAliases("test")).containsExactly("testAlias1");
registry.registerAlias("testAlias1", "testAlias2");
registry.registerAlias("testAlias2", "testAlias3");
assertThat(registry.getAliases("test")).containsExactlyInAnyOrder("testAlias1", "testAlias2", "testAlias3");
assertThat(registry.getAliases("testAlias1")).containsExactlyInAnyOrder("testAlias2", "testAlias3");
assertThat(registry.getAliases("testAlias2")).containsExactly("testAlias3");
assertThat(registry.getAliases("testAlias3")).isEmpty();
}
}
@@ -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,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-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import org.springframework.core.io.support.EncodedResource;
public class CannotReadScriptException extends ScriptException {
/**
* Create a new {@code CannotReadScriptException}.
* Construct a new {@code CannotReadScriptException}.
* @param resource the resource that cannot be read from
* @param cause the underlying cause of the resource access failure
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.springframework.util.Assert;
/**
* Composite {@link DatabasePopulator} that delegates to a list of given
* {@code DatabasePopulator} implementations, executing all scripts.
@@ -54,7 +52,6 @@ public class CompositeDatabasePopulator implements DatabasePopulator {
* @since 4.3
*/
public CompositeDatabasePopulator(Collection<DatabasePopulator> populators) {
Assert.notNull(populators, "DatabasePopulators must not be null");
this.populators.addAll(populators);
}
@@ -64,7 +61,6 @@ public class CompositeDatabasePopulator implements DatabasePopulator {
* @since 4.3
*/
public CompositeDatabasePopulator(DatabasePopulator... populators) {
Assert.notNull(populators, "DatabasePopulators must not be null");
this.populators.addAll(Arrays.asList(populators));
}
@@ -73,7 +69,6 @@ public class CompositeDatabasePopulator implements DatabasePopulator {
* Specify one or more populators to delegate to.
*/
public void setPopulators(DatabasePopulator... populators) {
Assert.notNull(populators, "DatabasePopulators must not be null");
this.populators.clear();
this.populators.addAll(Arrays.asList(populators));
}
@@ -82,13 +77,12 @@ public class CompositeDatabasePopulator implements DatabasePopulator {
* Add one or more populators to the list of delegates.
*/
public void addPopulators(DatabasePopulator... populators) {
Assert.notNull(populators, "DatabasePopulators must not be null");
this.populators.addAll(Arrays.asList(populators));
}
@Override
public void populate(Connection connection) throws SQLException, ScriptException {
Assert.notNull(connection, "Connection must not be null");
for (DatabasePopulator populator : this.populators) {
populator.populate(connection);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2014 the original author 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,7 @@ import org.springframework.lang.Nullable;
public abstract class ScriptException extends DataAccessException {
/**
* Create a new {@code ScriptException}.
* Constructor for {@code ScriptException}.
* @param message the detail message
*/
public ScriptException(String message) {
@@ -38,7 +38,7 @@ public abstract class ScriptException extends DataAccessException {
}
/**
* Create a new {@code ScriptException}.
* Constructor for {@code ScriptException}.
* @param message the detail message
* @param cause the root cause
*/
@@ -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.
@@ -29,7 +29,7 @@ import org.springframework.lang.Nullable;
public class ScriptParseException extends ScriptException {
/**
* Create a new {@code ScriptParseException}.
* Construct a new {@code ScriptParseException}.
* @param message detailed message
* @param resource the resource from which the SQL script was read
*/
@@ -38,7 +38,7 @@ public class ScriptParseException extends ScriptException {
}
/**
* Create a new {@code ScriptParseException}.
* Construct a new {@code ScriptParseException}.
* @param message detailed message
* @param resource the resource from which the SQL script was read
* @param cause the underlying cause of the failure
@@ -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.
@@ -35,7 +35,7 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Generic utility methods for working with SQL scripts in conjunction with JDBC.
* Generic utility methods for working with SQL scripts.
*
* <p>Mainly for internal use within the framework.
*
@@ -50,7 +50,6 @@ import org.springframework.util.StringUtils;
* @author Nicolas Debeissat
* @author Phillip Webb
* @since 4.0.3
* @see org.springframework.r2dbc.connection.init.ScriptUtils
*/
public abstract class ScriptUtils {
@@ -102,6 +101,349 @@ public abstract class ScriptUtils {
private static final Log logger = LogFactory.getLog(ScriptUtils.class);
/**
* Split an SQL script into separate statements delimited by the provided
* separator character. Each individual statement will be added to the
* provided {@code List}.
* <p>Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the
* comment prefix; any text beginning with the comment prefix and extending to
* the end of the line will be omitted from the output. Similarly,
* {@value #DEFAULT_BLOCK_COMMENT_START_DELIMITER} and
* {@value #DEFAULT_BLOCK_COMMENT_END_DELIMITER} will be used as the
* <em>start</em> and <em>end</em> block comment delimiters: any text enclosed
* in a block comment will be omitted from the output. In addition, multiple
* adjacent whitespace characters will be collapsed into a single space.
* @param script the SQL script
* @param separator character separating each statement (typically a ';')
* @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL script
* @see #splitSqlScript(String, String, List)
* @see #splitSqlScript(EncodedResource, String, String, String, String, String, List)
*/
public static void splitSqlScript(String script, char separator, List<String> statements) throws ScriptException {
splitSqlScript(script, String.valueOf(separator), statements);
}
/**
* Split an SQL script into separate statements delimited by the provided
* separator string. Each individual statement will be added to the
* provided {@code List}.
* <p>Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the
* comment prefix; any text beginning with the comment prefix and extending to
* the end of the line will be omitted from the output. Similarly,
* {@value #DEFAULT_BLOCK_COMMENT_START_DELIMITER} and
* {@value #DEFAULT_BLOCK_COMMENT_END_DELIMITER} will be used as the
* <em>start</em> and <em>end</em> block comment delimiters: any text enclosed
* in a block comment will be omitted from the output. In addition, multiple
* adjacent whitespace characters will be collapsed into a single space.
* @param script the SQL script
* @param separator text separating each statement
* (typically a ';' or newline character)
* @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL script
* @see #splitSqlScript(String, char, List)
* @see #splitSqlScript(EncodedResource, String, String, String, String, String, List)
*/
public static void splitSqlScript(String script, String separator, List<String> statements) throws ScriptException {
splitSqlScript(null, script, separator, DEFAULT_COMMENT_PREFIX, DEFAULT_BLOCK_COMMENT_START_DELIMITER,
DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements);
}
/**
* Split an SQL script into separate statements delimited by the provided
* separator string. Each individual statement will be added to the provided
* {@code List}.
* <p>Within the script, the provided {@code commentPrefix} will be honored:
* any text beginning with the comment prefix and extending to the end of the
* line will be omitted from the output. Similarly, the provided
* {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter}
* delimiters will be honored: any text enclosed in a block comment will be
* omitted from the output. In addition, multiple adjacent whitespace characters
* will be collapsed into a single space.
* @param resource the resource from which the script was read
* @param script the SQL script
* @param separator text separating each statement
* (typically a ';' or newline character)
* @param commentPrefix the prefix that identifies SQL line comments
* (typically "--")
* @param blockCommentStartDelimiter the <em>start</em> block comment delimiter;
* never {@code null} or empty
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter;
* never {@code null} or empty
* @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL script
*/
public static void splitSqlScript(@Nullable EncodedResource resource, String script,
String separator, String commentPrefix, String blockCommentStartDelimiter,
String blockCommentEndDelimiter, List<String> statements) throws ScriptException {
Assert.hasText(commentPrefix, "'commentPrefix' must not be null or empty");
splitSqlScript(resource, script, separator, new String[] { commentPrefix },
blockCommentStartDelimiter, blockCommentEndDelimiter, statements);
}
/**
* Split an SQL script into separate statements delimited by the provided
* separator string. Each individual statement will be added to the provided
* {@code List}.
* <p>Within the script, the provided {@code commentPrefixes} will be honored:
* any text beginning with one of the comment prefixes and extending to the
* end of the line will be omitted from the output. Similarly, the provided
* {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter}
* delimiters will be honored: any text enclosed in a block comment will be
* omitted from the output. In addition, multiple adjacent whitespace characters
* will be collapsed into a single space.
* @param resource the resource from which the script was read
* @param script the SQL script
* @param separator text separating each statement
* (typically a ';' or newline character)
* @param commentPrefixes the prefixes that identify SQL line comments
* (typically "--")
* @param blockCommentStartDelimiter the <em>start</em> block comment delimiter;
* never {@code null} or empty
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter;
* never {@code null} or empty
* @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL script
* @since 5.2
*/
public static void splitSqlScript(@Nullable EncodedResource resource, String script,
String separator, String[] commentPrefixes, String blockCommentStartDelimiter,
String blockCommentEndDelimiter, List<String> statements) throws ScriptException {
Assert.hasText(script, "'script' must not be null or empty");
Assert.notNull(separator, "'separator' must not be null");
Assert.notEmpty(commentPrefixes, "'commentPrefixes' must not be null or empty");
for (String commentPrefix : commentPrefixes) {
Assert.hasText(commentPrefix, "'commentPrefixes' must not contain null or empty elements");
}
Assert.hasText(blockCommentStartDelimiter, "'blockCommentStartDelimiter' must not be null or empty");
Assert.hasText(blockCommentEndDelimiter, "'blockCommentEndDelimiter' must not be null or empty");
StringBuilder sb = new StringBuilder();
boolean inSingleQuote = false;
boolean inDoubleQuote = false;
boolean inEscape = false;
for (int i = 0; i < script.length(); i++) {
char c = script.charAt(i);
if (inEscape) {
inEscape = false;
sb.append(c);
continue;
}
// MySQL style escapes
if (c == '\\') {
inEscape = true;
sb.append(c);
continue;
}
if (!inDoubleQuote && (c == '\'')) {
inSingleQuote = !inSingleQuote;
}
else if (!inSingleQuote && (c == '"')) {
inDoubleQuote = !inDoubleQuote;
}
if (!inSingleQuote && !inDoubleQuote) {
if (script.startsWith(separator, i)) {
// We've reached the end of the current statement
if (sb.length() > 0) {
statements.add(sb.toString());
sb = new StringBuilder();
}
i += separator.length() - 1;
continue;
}
else if (startsWithAny(script, commentPrefixes, i)) {
// Skip over any content from the start of the comment to the EOL
int indexOfNextNewline = script.indexOf('\n', i);
if (indexOfNextNewline > i) {
i = indexOfNextNewline;
continue;
}
else {
// If there's no EOL, we must be at the end of the script, so stop here.
break;
}
}
else if (script.startsWith(blockCommentStartDelimiter, i)) {
// Skip over any block comments
int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i);
if (indexOfCommentEnd > i) {
i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1;
continue;
}
else {
throw new ScriptParseException(
"Missing block comment end delimiter: " + blockCommentEndDelimiter, resource);
}
}
else if (c == ' ' || c == '\r' || c == '\n' || c == '\t') {
// Avoid multiple adjacent whitespace characters
if (sb.length() > 0 && sb.charAt(sb.length() - 1) != ' ') {
c = ' ';
}
else {
continue;
}
}
}
sb.append(c);
}
if (StringUtils.hasText(sb)) {
statements.add(sb.toString());
}
}
/**
* Read a script from the given resource, using "{@code --}" as the comment prefix
* and "{@code ;}" as the statement separator, and build a String containing the lines.
* @param resource the {@code EncodedResource} to be read
* @return {@code String} containing the script lines
* @throws IOException in case of I/O errors
*/
static String readScript(EncodedResource resource) throws IOException {
return readScript(resource, DEFAULT_COMMENT_PREFIXES, DEFAULT_STATEMENT_SEPARATOR, DEFAULT_BLOCK_COMMENT_END_DELIMITER);
}
/**
* Read a script from the provided resource, using the supplied comment prefixes
* and statement separator, and build a {@code String} containing the lines.
* <p>Lines <em>beginning</em> with one of the comment prefixes are excluded
* from the results; however, line comments anywhere else &mdash; for example,
* within a statement &mdash; will be included in the results.
* @param resource the {@code EncodedResource} containing the script
* to be processed
* @param commentPrefixes the prefixes that identify comments in the SQL script
* (typically "--")
* @param separator the statement separator in the SQL script (typically ";")
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
*/
private static String readScript(EncodedResource resource, @Nullable String[] commentPrefixes,
@Nullable String separator, @Nullable String blockCommentEndDelimiter) throws IOException {
try (LineNumberReader lnr = new LineNumberReader(resource.getReader())) {
return readScript(lnr, commentPrefixes, separator, blockCommentEndDelimiter);
}
}
/**
* Read a script from the provided {@code LineNumberReader}, using the supplied
* comment prefix and statement separator, and build a {@code String} containing
* the lines.
* <p>Lines <em>beginning</em> with the comment prefix are excluded from the
* results; however, line comments anywhere else &mdash; for example, within
* a statement &mdash; will be included in the results.
* @param lineNumberReader the {@code LineNumberReader} containing the script
* to be processed
* @param lineCommentPrefix the prefix that identifies comments in the SQL script
* (typically "--")
* @param separator the statement separator in the SQL script (typically ";")
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
*/
public static String readScript(LineNumberReader lineNumberReader, @Nullable String lineCommentPrefix,
@Nullable String separator, @Nullable String blockCommentEndDelimiter) throws IOException {
String[] lineCommentPrefixes = (lineCommentPrefix != null) ? new String[] { lineCommentPrefix } : null;
return readScript(lineNumberReader, lineCommentPrefixes, separator, blockCommentEndDelimiter);
}
/**
* Read a script from the provided {@code LineNumberReader}, using the supplied
* comment prefixes and statement separator, and build a {@code String} containing
* the lines.
* <p>Lines <em>beginning</em> with one of the comment prefixes are excluded
* from the results; however, line comments anywhere else &mdash; for example,
* within a statement &mdash; will be included in the results.
* @param lineNumberReader the {@code LineNumberReader} containing the script
* to be processed
* @param lineCommentPrefixes the prefixes that identify comments in the SQL script
* (typically "--")
* @param separator the statement separator in the SQL script (typically ";")
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
* @since 5.2
*/
public static String readScript(LineNumberReader lineNumberReader, @Nullable String[] lineCommentPrefixes,
@Nullable String separator, @Nullable String blockCommentEndDelimiter) throws IOException {
String currentStatement = lineNumberReader.readLine();
StringBuilder scriptBuilder = new StringBuilder();
while (currentStatement != null) {
if ((blockCommentEndDelimiter != null && currentStatement.contains(blockCommentEndDelimiter)) ||
(lineCommentPrefixes != null && !startsWithAny(currentStatement, lineCommentPrefixes, 0))) {
if (scriptBuilder.length() > 0) {
scriptBuilder.append('\n');
}
scriptBuilder.append(currentStatement);
}
currentStatement = lineNumberReader.readLine();
}
appendSeparatorToScriptIfNecessary(scriptBuilder, separator);
return scriptBuilder.toString();
}
private static void appendSeparatorToScriptIfNecessary(StringBuilder scriptBuilder, @Nullable String separator) {
if (separator == null) {
return;
}
String trimmed = separator.trim();
if (trimmed.length() == separator.length()) {
return;
}
// separator ends in whitespace, so we might want to see if the script is trying
// to end the same way
if (scriptBuilder.lastIndexOf(trimmed) == scriptBuilder.length() - trimmed.length()) {
scriptBuilder.append(separator.substring(trimmed.length()));
}
}
private static boolean startsWithAny(String script, String[] prefixes, int offset) {
for (String prefix : prefixes) {
if (script.startsWith(prefix, offset)) {
return true;
}
}
return false;
}
/**
* Does the provided SQL script contain the specified delimiter?
* @param script the SQL script
* @param delim the string delimiting each statement - typically a ';' character
*/
public static boolean containsSqlScriptDelimiters(String script, String delim) {
boolean inLiteral = false;
boolean inEscape = false;
for (int i = 0; i < script.length(); i++) {
char c = script.charAt(i);
if (inEscape) {
inEscape = false;
continue;
}
// MySQL style escapes
if (c == '\\') {
inEscape = true;
continue;
}
if (c == '\'') {
inLiteral = !inLiteral;
}
if (!inLiteral && script.startsWith(delim, i)) {
return true;
}
}
return false;
}
/**
* Execute the given SQL script using default settings for statement
* separators, comment delimiters, and exception handling flags.
@@ -233,7 +575,7 @@ public abstract class ScriptUtils {
String script;
try {
script = readScript(resource, separator, commentPrefixes, blockCommentEndDelimiter);
script = readScript(resource, commentPrefixes, separator, blockCommentEndDelimiter);
}
catch (IOException ex) {
throw new CannotReadScriptException(resource, ex);
@@ -242,9 +584,7 @@ public abstract class ScriptUtils {
if (separator == null) {
separator = DEFAULT_STATEMENT_SEPARATOR;
}
if (!EOF_STATEMENT_SEPARATOR.equals(separator) &&
!containsStatementSeparator(resource, script, separator, commentPrefixes,
blockCommentStartDelimiter, blockCommentEndDelimiter)) {
if (!EOF_STATEMENT_SEPARATOR.equals(separator) && !containsSqlScriptDelimiters(script, separator)) {
separator = FALLBACK_STATEMENT_SEPARATOR;
}
@@ -307,424 +647,4 @@ public abstract class ScriptUtils {
}
}
/**
* Read a script from the provided resource, using the supplied comment prefixes
* and statement separator, and build a {@code String} containing the lines.
* <p>Lines <em>beginning</em> with one of the comment prefixes are excluded
* from the results; however, line comments anywhere else &mdash; for example,
* within a statement &mdash; will be included in the results.
* @param resource the {@code EncodedResource} containing the script
* to be processed
* @param separator the statement separator in the SQL script (typically ";")
* @param commentPrefixes the prefixes that identify comments in the SQL script
* (typically "--")
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
*/
static String readScript(EncodedResource resource, @Nullable String separator,
String[] commentPrefixes, String blockCommentEndDelimiter) throws IOException {
try (LineNumberReader lnr = new LineNumberReader(resource.getReader())) {
return readScript(lnr, commentPrefixes, separator, blockCommentEndDelimiter);
}
}
/**
* Read a script from the provided {@code LineNumberReader}, using the supplied
* comment prefix and statement separator, and build a {@code String} containing
* the lines.
* <p>Lines <em>beginning</em> with the comment prefix are excluded from the
* results; however, line comments anywhere else &mdash; for example, within
* a statement &mdash; will be included in the results.
* @param lineNumberReader the {@code LineNumberReader} containing the script
* to be processed
* @param commentPrefix the prefix that identifies comments in the SQL script
* (typically "--")
* @param separator the statement separator in the SQL script (typically ";")
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
* @deprecated as of Spring Framework 5.2.16 with no plans for replacement.
* This is an internal API and will likely be removed in Spring Framework 6.0.
*/
@Deprecated
public static String readScript(LineNumberReader lineNumberReader, @Nullable String commentPrefix,
@Nullable String separator, @Nullable String blockCommentEndDelimiter) throws IOException {
String[] commentPrefixes = (commentPrefix != null) ? new String[] { commentPrefix } : null;
return readScript(lineNumberReader, commentPrefixes, separator, blockCommentEndDelimiter);
}
/**
* Read a script from the provided {@code LineNumberReader}, using the supplied
* comment prefixes and statement separator, and build a {@code String} containing
* the lines.
* <p>Lines <em>beginning</em> with one of the comment prefixes are excluded
* from the results; however, line comments anywhere else &mdash; for example,
* within a statement &mdash; will be included in the results.
* @param lineNumberReader the {@code LineNumberReader} containing the script
* to be processed
* @param commentPrefixes the prefixes that identify comments in the SQL script
* (typically "--")
* @param separator the statement separator in the SQL script (typically ";")
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
* @since 5.2
* @deprecated as of Spring Framework 5.2.16 with no plans for replacement.
* This is an internal API and will likely be removed in Spring Framework 6.0.
*/
@Deprecated
public static String readScript(LineNumberReader lineNumberReader, @Nullable String[] commentPrefixes,
@Nullable String separator, @Nullable String blockCommentEndDelimiter) throws IOException {
String currentStatement = lineNumberReader.readLine();
StringBuilder scriptBuilder = new StringBuilder();
while (currentStatement != null) {
if ((blockCommentEndDelimiter != null && currentStatement.contains(blockCommentEndDelimiter)) ||
(commentPrefixes != null && !startsWithAny(currentStatement, commentPrefixes, 0))) {
if (scriptBuilder.length() > 0) {
scriptBuilder.append('\n');
}
scriptBuilder.append(currentStatement);
}
currentStatement = lineNumberReader.readLine();
}
appendSeparatorToScriptIfNecessary(scriptBuilder, separator);
return scriptBuilder.toString();
}
private static void appendSeparatorToScriptIfNecessary(StringBuilder scriptBuilder, @Nullable String separator) {
if (separator == null) {
return;
}
String trimmed = separator.trim();
if (trimmed.length() == separator.length()) {
return;
}
// separator ends in whitespace, so we might want to see if the script is trying
// to end the same way
if (scriptBuilder.lastIndexOf(trimmed) == scriptBuilder.length() - trimmed.length()) {
scriptBuilder.append(separator.substring(trimmed.length()));
}
}
/**
* Determine if the provided SQL script contains the specified delimiter.
* <p>This method is intended to be used to find the string delimiting each
* SQL statement &mdash; for example, a ';' character.
* <p>Any occurrence of the delimiter within the script will be ignored if it
* is within a <em>literal</em> block of text enclosed in single quotes
* ({@code '}) or double quotes ({@code "}), if it is escaped with a backslash
* ({@code \}), or if it is within a single-line comment or block comment.
* @param script the SQL script to search within
* @param delimiter the statement delimiter to search for
* @see #DEFAULT_COMMENT_PREFIXES
* @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER
* @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER
* @deprecated as of Spring Framework 5.2.16 with no plans for replacement.
* This is an internal API and will likely be removed in Spring Framework 6.0.
*/
@Deprecated
public static boolean containsSqlScriptDelimiters(String script, String delimiter) {
return containsStatementSeparator(null, script, delimiter, DEFAULT_COMMENT_PREFIXES,
DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER);
}
/**
* Determine if the provided SQL script contains the specified statement separator.
* <p>This method is intended to be used to find the string separating each
* SQL statement &mdash; for example, a ';' character.
* <p>Any occurrence of the separator within the script will be ignored if it
* is within a <em>literal</em> block of text enclosed in single quotes
* ({@code '}) or double quotes ({@code "}), if it is escaped with a backslash
* ({@code \}), or if it is within a single-line comment or block comment.
* @param resource the resource from which the script was read, or {@code null}
* if unknown
* @param script the SQL script to search within
* @param separator the statement separator to search for
* @param commentPrefixes the prefixes that identify single-line comments
* (typically {@code "--"})
* @param blockCommentStartDelimiter the <em>start</em> block comment delimiter
* (typically {@code "/*"})
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
* (typically <code>"*&#47;"</code>)
* @since 5.2.16
*/
private static boolean containsStatementSeparator(@Nullable EncodedResource resource, String script,
String separator, String[] commentPrefixes, String blockCommentStartDelimiter,
String blockCommentEndDelimiter) throws ScriptException {
boolean inSingleQuote = false;
boolean inDoubleQuote = false;
boolean inEscape = false;
for (int i = 0; i < script.length(); i++) {
char c = script.charAt(i);
if (inEscape) {
inEscape = false;
continue;
}
// MySQL style escapes
if (c == '\\') {
inEscape = true;
continue;
}
if (!inDoubleQuote && (c == '\'')) {
inSingleQuote = !inSingleQuote;
}
else if (!inSingleQuote && (c == '"')) {
inDoubleQuote = !inDoubleQuote;
}
if (!inSingleQuote && !inDoubleQuote) {
if (script.startsWith(separator, i)) {
return true;
}
else if (startsWithAny(script, commentPrefixes, i)) {
// Skip over any content from the start of the comment to the EOL
int indexOfNextNewline = script.indexOf('\n', i);
if (indexOfNextNewline > i) {
i = indexOfNextNewline;
continue;
}
else {
// If there's no EOL, we must be at the end of the script, so stop here.
break;
}
}
else if (script.startsWith(blockCommentStartDelimiter, i)) {
// Skip over any block comments
int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i);
if (indexOfCommentEnd > i) {
i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1;
continue;
}
else {
throw new ScriptParseException(
"Missing block comment end delimiter: " + blockCommentEndDelimiter, resource);
}
}
}
}
return false;
}
/**
* Split an SQL script into separate statements delimited by the provided
* separator character. Each individual statement will be added to the
* provided {@code List}.
* <p>Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the
* comment prefix; any text beginning with the comment prefix and extending to
* the end of the line will be omitted from the output. Similarly,
* {@value #DEFAULT_BLOCK_COMMENT_START_DELIMITER} and
* {@value #DEFAULT_BLOCK_COMMENT_END_DELIMITER} will be used as the
* <em>start</em> and <em>end</em> block comment delimiters: any text enclosed
* in a block comment will be omitted from the output. In addition, multiple
* adjacent whitespace characters will be collapsed into a single space.
* @param script the SQL script
* @param separator character separating each statement (typically a ';')
* @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL script
* @see #splitSqlScript(String, String, List)
* @see #splitSqlScript(EncodedResource, String, String, String, String, String, List)
* @deprecated as of Spring Framework 5.2.16 with no plans for replacement.
* This is an internal API and will likely be removed in Spring Framework 6.0.
*/
@Deprecated
public static void splitSqlScript(String script, char separator, List<String> statements) throws ScriptException {
splitSqlScript(script, String.valueOf(separator), statements);
}
/**
* Split an SQL script into separate statements delimited by the provided
* separator string. Each individual statement will be added to the
* provided {@code List}.
* <p>Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the
* comment prefix; any text beginning with the comment prefix and extending to
* the end of the line will be omitted from the output. Similarly,
* {@value #DEFAULT_BLOCK_COMMENT_START_DELIMITER} and
* {@value #DEFAULT_BLOCK_COMMENT_END_DELIMITER} will be used as the
* <em>start</em> and <em>end</em> block comment delimiters: any text enclosed
* in a block comment will be omitted from the output. In addition, multiple
* adjacent whitespace characters will be collapsed into a single space.
* @param script the SQL script
* @param separator text separating each statement
* (typically a ';' or newline character)
* @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL script
* @see #splitSqlScript(String, char, List)
* @see #splitSqlScript(EncodedResource, String, String, String, String, String, List)
* @deprecated as of Spring Framework 5.2.16 with no plans for replacement.
* This is an internal API and will likely be removed in Spring Framework 6.0.
*/
@Deprecated
public static void splitSqlScript(String script, String separator, List<String> statements) throws ScriptException {
splitSqlScript(null, script, separator, DEFAULT_COMMENT_PREFIX, DEFAULT_BLOCK_COMMENT_START_DELIMITER,
DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements);
}
/**
* Split an SQL script into separate statements delimited by the provided
* separator string. Each individual statement will be added to the provided
* {@code List}.
* <p>Within the script, the provided {@code commentPrefix} will be honored:
* any text beginning with the comment prefix and extending to the end of the
* line will be omitted from the output. Similarly, the provided
* {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter}
* delimiters will be honored: any text enclosed in a block comment will be
* omitted from the output. In addition, multiple adjacent whitespace characters
* will be collapsed into a single space.
* @param resource the resource from which the script was read
* @param script the SQL script
* @param separator text separating each statement
* (typically a ';' or newline character)
* @param commentPrefix the prefix that identifies SQL line comments
* (typically "--")
* @param blockCommentStartDelimiter the <em>start</em> block comment delimiter;
* never {@code null} or empty
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter;
* never {@code null} or empty
* @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL script
* @deprecated as of Spring Framework 5.2.16 with no plans for replacement.
* This is an internal API and will likely be removed in Spring Framework 6.0.
*/
@Deprecated
public static void splitSqlScript(@Nullable EncodedResource resource, String script,
String separator, String commentPrefix, String blockCommentStartDelimiter,
String blockCommentEndDelimiter, List<String> statements) throws ScriptException {
Assert.hasText(commentPrefix, "'commentPrefix' must not be null or empty");
splitSqlScript(resource, script, separator, new String[] { commentPrefix },
blockCommentStartDelimiter, blockCommentEndDelimiter, statements);
}
/**
* Split an SQL script into separate statements delimited by the provided
* separator string. Each individual statement will be added to the provided
* {@code List}.
* <p>Within the script, the provided {@code commentPrefixes} will be honored:
* any text beginning with one of the comment prefixes and extending to the
* end of the line will be omitted from the output. Similarly, the provided
* {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter}
* delimiters will be honored: any text enclosed in a block comment will be
* omitted from the output. In addition, multiple adjacent whitespace characters
* will be collapsed into a single space.
* @param resource the resource from which the script was read
* @param script the SQL script
* @param separator text separating each statement
* (typically a ';' or newline character)
* @param commentPrefixes the prefixes that identify SQL line comments
* (typically "--")
* @param blockCommentStartDelimiter the <em>start</em> block comment delimiter;
* never {@code null} or empty
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter;
* never {@code null} or empty
* @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL script
* @since 5.2
* @deprecated as of Spring Framework 5.2.16 with no plans for replacement.
* This is an internal API and will likely be removed in Spring Framework 6.0.
*/
@Deprecated
public static void splitSqlScript(@Nullable EncodedResource resource, String script,
String separator, String[] commentPrefixes, String blockCommentStartDelimiter,
String blockCommentEndDelimiter, List<String> statements) throws ScriptException {
Assert.hasText(script, "'script' must not be null or empty");
Assert.notNull(separator, "'separator' must not be null");
Assert.notEmpty(commentPrefixes, "'commentPrefixes' must not be null or empty");
for (String commentPrefix : commentPrefixes) {
Assert.hasText(commentPrefix, "'commentPrefixes' must not contain null or empty elements");
}
Assert.hasText(blockCommentStartDelimiter, "'blockCommentStartDelimiter' must not be null or empty");
Assert.hasText(blockCommentEndDelimiter, "'blockCommentEndDelimiter' must not be null or empty");
StringBuilder sb = new StringBuilder();
boolean inSingleQuote = false;
boolean inDoubleQuote = false;
boolean inEscape = false;
for (int i = 0; i < script.length(); i++) {
char c = script.charAt(i);
if (inEscape) {
inEscape = false;
sb.append(c);
continue;
}
// MySQL style escapes
if (c == '\\') {
inEscape = true;
sb.append(c);
continue;
}
if (!inDoubleQuote && (c == '\'')) {
inSingleQuote = !inSingleQuote;
}
else if (!inSingleQuote && (c == '"')) {
inDoubleQuote = !inDoubleQuote;
}
if (!inSingleQuote && !inDoubleQuote) {
if (script.startsWith(separator, i)) {
// We've reached the end of the current statement
if (sb.length() > 0) {
statements.add(sb.toString());
sb = new StringBuilder();
}
i += separator.length() - 1;
continue;
}
else if (startsWithAny(script, commentPrefixes, i)) {
// Skip over any content from the start of the comment to the EOL
int indexOfNextNewline = script.indexOf('\n', i);
if (indexOfNextNewline > i) {
i = indexOfNextNewline;
continue;
}
else {
// If there's no EOL, we must be at the end of the script, so stop here.
break;
}
}
else if (script.startsWith(blockCommentStartDelimiter, i)) {
// Skip over any block comments
int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i);
if (indexOfCommentEnd > i) {
i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1;
continue;
}
else {
throw new ScriptParseException(
"Missing block comment end delimiter: " + blockCommentEndDelimiter, resource);
}
}
else if (c == ' ' || c == '\r' || c == '\n' || c == '\t') {
// Avoid multiple adjacent whitespace characters
if (sb.length() > 0 && sb.charAt(sb.length() - 1) != ' ') {
c = ' ';
}
else {
continue;
}
}
}
sb.append(c);
}
if (StringUtils.hasText(sb)) {
statements.add(sb.toString());
}
}
private static boolean startsWithAny(String script, String[] prefixes, int offset) {
for (String prefix : prefixes) {
if (script.startsWith(prefix, offset)) {
return true;
}
}
return false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2014 the original author 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 @@ package org.springframework.jdbc.datasource.init;
public class UncategorizedScriptException extends ScriptException {
/**
* Create a new {@code UncategorizedScriptException}.
* Construct a new {@code UncategorizedScriptException}.
* @param message detailed message
*/
public UncategorizedScriptException(String message) {
@@ -36,7 +36,7 @@ public class UncategorizedScriptException extends ScriptException {
}
/**
* Create a new {@code UncategorizedScriptException}.
* Construct a new {@code UncategorizedScriptException}.
* @param message detailed message
* @param cause the root cause
*/
@@ -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.
@@ -29,13 +29,15 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import static org.assertj.core.api.Assertions.assertThat;
/**
* Abstract base class for integration tests involving database initialization.
*
* @author Sam Brannen
* @since 4.0.3
*/
abstract class AbstractDatabaseInitializationTests {
public abstract class AbstractDatabaseInitializationTests {
private final ClassRelativeResourceLoader resourceLoader = new ClassRelativeResourceLoader(getClass());
@@ -45,13 +47,13 @@ abstract class AbstractDatabaseInitializationTests {
@BeforeEach
void setUp() {
public void setUp() {
db = new EmbeddedDatabaseBuilder().setType(getEmbeddedDatabaseType()).build();
jdbcTemplate = new JdbcTemplate(db);
}
@AfterEach
void shutDown() {
public void shutDown() {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.clear();
TransactionSynchronizationManager.unbindResource(db);
@@ -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.
@@ -34,7 +34,7 @@ import static org.mockito.Mockito.verify;
* @author Juergen Hoeller
* @since 4.3
*/
class CompositeDatabasePopulatorTests {
public class CompositeDatabasePopulatorTests {
private final Connection mockedConnection = mock(Connection.class);
@@ -44,59 +44,49 @@ class CompositeDatabasePopulatorTests {
@Test
void addPopulators() throws SQLException {
public void addPopulators() throws SQLException {
CompositeDatabasePopulator populator = new CompositeDatabasePopulator();
populator.addPopulators(mockedDatabasePopulator1, mockedDatabasePopulator2);
populator.populate(mockedConnection);
verify(mockedDatabasePopulator1, times(1)).populate(mockedConnection);
verify(mockedDatabasePopulator1,times(1)).populate(mockedConnection);
verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection);
}
@Test
void setPopulatorsWithMultiple() throws SQLException {
public void setPopulatorsWithMultiple() throws SQLException {
CompositeDatabasePopulator populator = new CompositeDatabasePopulator();
populator.setPopulators(mockedDatabasePopulator1, mockedDatabasePopulator2); // multiple
populator.populate(mockedConnection);
verify(mockedDatabasePopulator1, times(1)).populate(mockedConnection);
verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection);
}
@Test
void setPopulatorsForOverride() throws SQLException {
public void setPopulatorsForOverride() throws SQLException {
CompositeDatabasePopulator populator = new CompositeDatabasePopulator();
populator.setPopulators(mockedDatabasePopulator1);
populator.setPopulators(mockedDatabasePopulator2); // override
populator.populate(mockedConnection);
verify(mockedDatabasePopulator1, times(0)).populate(mockedConnection);
verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection);
}
@Test
void constructWithVarargs() throws SQLException {
public void constructWithVarargs() throws SQLException {
CompositeDatabasePopulator populator =
new CompositeDatabasePopulator(mockedDatabasePopulator1, mockedDatabasePopulator2);
populator.populate(mockedConnection);
verify(mockedDatabasePopulator1, times(1)).populate(mockedConnection);
verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection);
}
@Test
void constructWithCollection() throws SQLException {
public void constructWithCollection() throws SQLException {
Set<DatabasePopulator> populators = new LinkedHashSet<>();
populators.add(mockedDatabasePopulator1);
populators.add(mockedDatabasePopulator2);
CompositeDatabasePopulator populator = new CompositeDatabasePopulator(populators);
populator.populate(mockedConnection);
verify(mockedDatabasePopulator1, times(1)).populate(mockedConnection);
verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection);
}
@@ -26,7 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Sam Brannen
* @since 4.0.3
*/
class H2DatabasePopulatorIntegrationTests extends AbstractDatabasePopulatorTests {
class H2DatabasePopulatorTests extends AbstractDatabasePopulatorTests {
@Override
protected EmbeddedDatabaseType getEmbeddedDatabaseType() {
@@ -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.
@@ -17,12 +17,12 @@
package org.springframework.jdbc.datasource.init;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.core.io.Resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.mock;
/**
* Unit tests for {@link ResourceDatabasePopulator}.
@@ -31,84 +31,84 @@ import static org.mockito.BDDMockito.mock;
* @since 4.1
* @see AbstractDatabasePopulatorTests
*/
class ResourceDatabasePopulatorUnitTests {
public class ResourceDatabasePopulatorTests {
private static final Resource script1 = mock(Resource.class);
private static final Resource script2 = mock(Resource.class);
private static final Resource script3 = mock(Resource.class);
private static final Resource script1 = Mockito.mock(Resource.class);
private static final Resource script2 = Mockito.mock(Resource.class);
private static final Resource script3 = Mockito.mock(Resource.class);
@Test
void constructWithNullResource() {
public void constructWithNullResource() {
assertThatIllegalArgumentException().isThrownBy(() ->
new ResourceDatabasePopulator((Resource) null));
}
@Test
void constructWithNullResourceArray() {
public void constructWithNullResourceArray() {
assertThatIllegalArgumentException().isThrownBy(() ->
new ResourceDatabasePopulator((Resource[]) null));
}
@Test
void constructWithResource() {
public void constructWithResource() {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(script1);
assertThat(databasePopulator.scripts).hasSize(1);
assertThat(databasePopulator.scripts.size()).isEqualTo(1);
}
@Test
void constructWithMultipleResources() {
public void constructWithMultipleResources() {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(script1, script2);
assertThat(databasePopulator.scripts).hasSize(2);
assertThat(databasePopulator.scripts.size()).isEqualTo(2);
}
@Test
void constructWithMultipleResourcesAndThenAddScript() {
public void constructWithMultipleResourcesAndThenAddScript() {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(script1, script2);
assertThat(databasePopulator.scripts).hasSize(2);
assertThat(databasePopulator.scripts.size()).isEqualTo(2);
databasePopulator.addScript(script3);
assertThat(databasePopulator.scripts).hasSize(3);
assertThat(databasePopulator.scripts.size()).isEqualTo(3);
}
@Test
void addScriptsWithNullResource() {
public void addScriptsWithNullResource() {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
assertThatIllegalArgumentException().isThrownBy(() ->
databasePopulator.addScripts((Resource) null));
}
@Test
void addScriptsWithNullResourceArray() {
public void addScriptsWithNullResourceArray() {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
assertThatIllegalArgumentException().isThrownBy(() ->
databasePopulator.addScripts((Resource[]) null));
}
@Test
void setScriptsWithNullResource() {
public void setScriptsWithNullResource() {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
assertThatIllegalArgumentException().isThrownBy(() ->
databasePopulator.setScripts((Resource) null));
}
@Test
void setScriptsWithNullResourceArray() {
public void setScriptsWithNullResourceArray() {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
assertThatIllegalArgumentException().isThrownBy(() ->
databasePopulator.setScripts((Resource[]) null));
}
@Test
void setScriptsAndThenAddScript() {
public void setScriptsAndThenAddScript() {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
assertThat(databasePopulator.scripts).isEmpty();
assertThat(databasePopulator.scripts.size()).isEqualTo(0);
databasePopulator.setScripts(script1, script2);
assertThat(databasePopulator.scripts).hasSize(2);
assertThat(databasePopulator.scripts.size()).isEqualTo(2);
databasePopulator.addScript(script3);
assertThat(databasePopulator.scripts).hasSize(3);
assertThat(databasePopulator.scripts.size()).isEqualTo(3);
}
}
@@ -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,10 +19,7 @@ package org.springframework.jdbc.datasource.init;
import java.util.ArrayList;
import java.util.List;
import org.assertj.core.util.Strings;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.EncodedResource;
@@ -49,7 +46,6 @@ import static org.springframework.jdbc.datasource.init.ScriptUtils.splitSqlScrip
public class ScriptUtilsUnitTests {
@Test
@SuppressWarnings("deprecation")
public void splitSqlScriptDelimitedWithSemicolon() {
String rawStatement1 = "insert into customer (id, name)\nvalues (1, 'Rod ; Johnson'), (2, 'Adrian \n Collier')";
String cleanedStatement1 = "insert into customer (id, name) values (1, 'Rod ; Johnson'), (2, 'Adrian \n Collier')";
@@ -57,72 +53,54 @@ public class ScriptUtilsUnitTests {
String cleanedStatement2 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)";
String rawStatement3 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)";
String cleanedStatement3 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)";
String delimiter = ";";
String script = Strings.join(rawStatement1, rawStatement2, rawStatement3).with(delimiter);
char delim = ';';
String script = rawStatement1 + delim + rawStatement2 + delim + rawStatement3 + delim;
List<String> statements = new ArrayList<>();
splitSqlScript(script, delimiter, statements);
splitSqlScript(script, delim, statements);
assertThat(statements).containsExactly(cleanedStatement1, cleanedStatement2, cleanedStatement3);
}
@Test
@SuppressWarnings("deprecation")
public void splitSqlScriptDelimitedWithNewLine() {
String statement1 = "insert into customer (id, name) values (1, 'Rod ; Johnson'), (2, 'Adrian \n Collier')";
String statement2 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)";
String statement3 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)";
String delimiter = "\n";
String script = Strings.join(statement1, statement2, statement3).with(delimiter);
char delim = '\n';
String script = statement1 + delim + statement2 + delim + statement3 + delim;
List<String> statements = new ArrayList<>();
splitSqlScript(script, delimiter, statements);
splitSqlScript(script, delim, statements);
assertThat(statements).containsExactly(statement1, statement2, statement3);
}
@Test
@SuppressWarnings("deprecation")
public void splitSqlScriptDelimitedWithNewLineButDefaultDelimiterSpecified() {
String statement1 = "do something";
String statement2 = "do something else";
String script = Strings.join(statement1, statement2).with("\n");
char delim = '\n';
String script = statement1 + delim + statement2 + delim;
List<String> statements = new ArrayList<>();
splitSqlScript(script, DEFAULT_STATEMENT_SEPARATOR, statements);
assertThat(statements).as("stripped but not split statements").containsExactly(script.replace('\n', ' '));
}
@Test // SPR-13218
@SuppressWarnings("deprecation")
public void splitScriptWithSingleQuotesNestedInsideDoubleQuotes() {
public void splitScriptWithSingleQuotesNestedInsideDoubleQuotes() throws Exception {
String statement1 = "select '1' as \"Dogbert's owner's\" from dual";
String statement2 = "select '2' as \"Dilbert's\" from dual";
String delimiter = ";";
String script = Strings.join(statement1, statement2).with(delimiter);
char delim = ';';
String script = statement1 + delim + statement2 + delim;
List<String> statements = new ArrayList<>();
splitSqlScript(script, delimiter, statements);
splitSqlScript(script, ';', statements);
assertThat(statements).containsExactly(statement1, statement2);
}
@Test // SPR-11560
@SuppressWarnings("deprecation")
public void readAndSplitScriptWithMultipleNewlinesAsSeparator() throws Exception {
String script = readScript("db-test-data-multi-newline.sql");
List<String> statements = new ArrayList<>();
splitSqlScript(script, "\n\n", statements);
String statement1 = "insert into T_TEST (NAME) values ('Keith')";
String statement2 = "insert into T_TEST (NAME) values ('Dave')";
assertThat(statements).containsExactly(statement1, statement2);
}
@@ -144,103 +122,65 @@ public class ScriptUtilsUnitTests {
splitScriptContainingComments(script, "--", "#", "^");
}
@SuppressWarnings("deprecation")
private void splitScriptContainingComments(String script, String... commentPrefixes) {
private void splitScriptContainingComments(String script, String... commentPrefixes) throws Exception {
List<String> statements = new ArrayList<>();
splitSqlScript(null, script, ";", commentPrefixes, DEFAULT_BLOCK_COMMENT_START_DELIMITER,
DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements);
String statement1 = "insert into customer (id, name) values (1, 'Rod; Johnson'), (2, 'Adrian Collier')";
String statement2 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)";
String statement3 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)";
// Statement 4 addresses the error described in SPR-9982.
String statement4 = "INSERT INTO persons( person_id , name) VALUES( 1 , 'Name' )";
assertThat(statements).containsExactly(statement1, statement2, statement3, statement4);
}
@Test // SPR-10330
@SuppressWarnings("deprecation")
public void readAndSplitScriptContainingCommentsWithLeadingTabs() throws Exception {
String script = readScript("test-data-with-comments-and-leading-tabs.sql");
List<String> statements = new ArrayList<>();
splitSqlScript(script, ';', statements);
String statement1 = "insert into customer (id, name) values (1, 'Sam Brannen')";
String statement2 = "insert into orders(id, order_date, customer_id) values (1, '2013-06-08', 1)";
String statement3 = "insert into orders(id, order_date, customer_id) values (2, '2013-06-08', 1)";
assertThat(statements).containsExactly(statement1, statement2, statement3);
}
@Test // SPR-9531
@SuppressWarnings("deprecation")
public void readAndSplitScriptContainingMultiLineComments() throws Exception {
String script = readScript("test-data-with-multi-line-comments.sql");
List<String> statements = new ArrayList<>();
splitSqlScript(script, ';', statements);
String statement1 = "INSERT INTO users(first_name, last_name) VALUES('Juergen', 'Hoeller')";
String statement2 = "INSERT INTO users(first_name, last_name) VALUES( 'Sam' , 'Brannen' )";
assertThat(statements).containsExactly(statement1, statement2);
}
@Test
@SuppressWarnings("deprecation")
public void readAndSplitScriptContainingMultiLineNestedComments() throws Exception {
String script = readScript("test-data-with-multi-line-nested-comments.sql");
List<String> statements = new ArrayList<>();
splitSqlScript(script, ';', statements);
String statement1 = "INSERT INTO users(first_name, last_name) VALUES('Juergen', 'Hoeller')";
String statement2 = "INSERT INTO users(first_name, last_name) VALUES( 'Sam' , 'Brannen' )";
assertThat(statements).containsExactly(statement1, statement2);
}
@ParameterizedTest
@CsvSource(delimiter = '#', value = {
// semicolon
"'select 1\n select '';''' # ; # false",
"'select 1\n select \";\"' # ; # false",
"'select 1; select 2' # ; # true",
// newline
"'select 1; select ''\n''' # '\n' # false",
"'select 1; select \"\n\"' # '\n' # false",
"'select 1\n select 2' # '\n' # true",
// double newline
"'select 1\n select 2' # '\n\n' # false",
"'select 1\n\n select 2' # '\n\n' # true",
// semicolon with MySQL style escapes '\\'
"'insert into users(first, last)\nvalues(''a\\\\'', ''b;'')' # ; # false",
"'insert into users(first, last)\nvalues(''Charles'', ''d\\''Artagnan''); select 1' # ; # true",
// semicolon inside comments
"'-- a;b;c\ninsert into colors(color_num) values(42);' # ; # true",
"'/* a;b;c */\ninsert into colors(color_num) values(42);' # ; # true",
"'-- a;b;c\ninsert into colors(color_num) values(42)' # ; # false",
"'/* a;b;c */\ninsert into colors(color_num) values(42)' # ; # false",
// single quotes inside comments
"'-- What\\''s your favorite color?\ninsert into colors(color_num) values(42);' # ; # true",
"'-- What''s your favorite color?\ninsert into colors(color_num) values(42);' # ; # true",
"'/* What\\''s your favorite color? */\ninsert into colors(color_num) values(42);' # ; # true",
"'/* What''s your favorite color? */\ninsert into colors(color_num) values(42);' # ; # true",
// double quotes inside comments
"'-- double \" quotes\ninsert into colors(color_num) values(42);' # ; # true",
"'-- double \\\" quotes\ninsert into colors(color_num) values(42);' # ; # true",
"'/* double \" quotes */\ninsert into colors(color_num) values(42);' # ; # true",
"'/* double \\\" quotes */\ninsert into colors(color_num) values(42);' # ; # true"
})
@SuppressWarnings("deprecation")
public void containsStatementSeparator(String script, String delimiter, boolean expected) {
// Indirectly tests ScriptUtils.containsStatementSeparator(EncodedResource, String, String, String[], String, String).
assertThat(containsSqlScriptDelimiters(script, delimiter)).isEqualTo(expected);
@Test
public void containsDelimiters() {
assertThat(containsSqlScriptDelimiters("select 1\n select ';'", ";")).isFalse();
assertThat(containsSqlScriptDelimiters("select 1; select 2", ";")).isTrue();
assertThat(containsSqlScriptDelimiters("select 1; select '\\n\n';", "\n")).isFalse();
assertThat(containsSqlScriptDelimiters("select 1\n select 2", "\n")).isTrue();
assertThat(containsSqlScriptDelimiters("select 1\n select 2", "\n\n")).isFalse();
assertThat(containsSqlScriptDelimiters("select 1\n\n select 2", "\n\n")).isTrue();
// MySQL style escapes '\\'
assertThat(containsSqlScriptDelimiters("insert into users(first_name, last_name)\nvalues('a\\\\', 'b;')", ";")).isFalse();
assertThat(containsSqlScriptDelimiters("insert into users(first_name, last_name)\nvalues('Charles', 'd\\'Artagnan'); select 1;", ";")).isTrue();
}
private String readScript(String path) throws Exception {
EncodedResource resource = new EncodedResource(new ClassPathResource(path, getClass()));
return ScriptUtils.readScript(resource, DEFAULT_STATEMENT_SEPARATOR, DEFAULT_COMMENT_PREFIXES,
DEFAULT_BLOCK_COMMENT_END_DELIMITER);
return ScriptUtils.readScript(resource);
}
}
@@ -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);
@@ -5,19 +5,16 @@
* x, y, z...
*/
-- This is a single line comment containing single (') and double quotes (").
INSERT INTO users(first_name, last_name) VALUES('Juergen', 'Hoeller');
-- This is also a comment.
/*-------------------------------------------
-- A fancy multi-line comment that puts
-- A fancy multi-line comments that puts
-- single line comments inside of a multi-line
-- comment block.
Moreover, the block comment end delimiter
appears on a line that can potentially also
be a single-line comment if we weren't
already inside a multi-line comment run.
And here's a line containing single and double quotes (").
-------------------------------------------*/
INSERT INTO
users(first_name, last_name) -- This is a single line comment containing the block-end-comment sequence here */ but it's still a single-line comment
@@ -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.
*/
@@ -423,7 +406,6 @@ public class CachingConnectionFactory extends SingleConnectionFactory {
return new CachedMessageProducer(producer);
}
@SuppressWarnings("resource")
private MessageConsumer getCachedConsumer(Destination dest, @Nullable String selector,
@Nullable Boolean noLocal, @Nullable String subscription, boolean durable) throws JMSException {
@@ -120,7 +120,8 @@ public class DefaultMessageHandlerMethodFactory
* the ones configured by default. This is an advanced option. For most use cases
* it should be sufficient to use {@link #setCustomArgumentResolvers(java.util.List)}.
*/
public void setArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
@SuppressWarnings("ConstantConditions")
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
if (argumentResolvers == null) {
this.argumentResolvers.clear();
return;
@@ -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.
@@ -131,6 +131,7 @@ public class RSocketFrameTypeMessageCondition extends AbstractMessageCondition<R
* @param message the current message
* @return the frame type or {@code null} if not found
*/
@SuppressWarnings("ConstantConditions")
@Nullable
public static FrameType getFrameType(Message<?> message) {
return (FrameType) message.getHeaders().get(RSocketFrameTypeMessageCondition.FRAME_TYPE_HEADER);
@@ -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) {
@@ -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.
@@ -29,8 +29,8 @@ import org.springframework.util.Assert;
* Base class for STOMP client implementations.
*
* <p>Subclasses can connect over WebSocket or TCP using any library. When creating
* a new connection, a subclass can create an instance of {@link DefaultStompSession}
* which implements {@link org.springframework.messaging.tcp.TcpConnectionHandler}
* a new connection, a subclass can create an instance of @link DefaultStompSession}
* which extends {@link org.springframework.messaging.tcp.TcpConnectionHandler}
* whose lifecycle methods the subclass must then invoke.
*
* <p>In effect, {@code TcpConnectionHandler} and {@code TcpConnection} are the
@@ -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.
@@ -102,7 +102,6 @@ inline fun <reified T : Any> RSocketRequester.RequestSpec.dataWithType(flow: Flo
* @author Sebastien Deleuze
* @since 5.2
*/
@Suppress("DEPRECATION")
suspend fun RSocketRequester.RetrieveSpec.sendAndAwait() {
send().awaitSingleOrNull()
}
@@ -122,7 +121,6 @@ suspend inline fun <reified T : Any> RSocketRequester.RetrieveSpec.retrieveAndAw
* @author Sebastien Deleuze
* @since 5.2.1
*/
@Suppress("DEPRECATION")
suspend inline fun <reified T : Any> RSocketRequester.RetrieveSpec.retrieveAndAwaitOrNull(): T? =
retrieveMono(object : ParameterizedTypeReference<T>() {}).awaitSingleOrNull()
@@ -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();
+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"

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