From 8e48728018d707b55d629ce18e5e15dc83148bbf Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 13 Dec 2023 11:41:58 +0100 Subject: [PATCH 01/55] Update workflows --- .github/release-files-spec.json | 28 ------- .../artifactory-milestone-release.yml | 38 --------- .github/workflows/artifactory-staging.yml | 4 +- .github/workflows/continuous-inspection.yml | 32 ------- ...ion.yml => continuous-integration-51x.yml} | 15 ++-- .github/workflows/deploy-docs.yml | 30 ------- .github/workflows/documentation-upload.yml | 8 +- .github/workflows/maven-central-release.yml | 83 ------------------- .github/workflows/maven-central-stage.yml | 58 ------------- .../workflows/release-notes-generation.yml | 54 ------------ 10 files changed, 17 insertions(+), 333 deletions(-) delete mode 100644 .github/release-files-spec.json delete mode 100644 .github/workflows/artifactory-milestone-release.yml delete mode 100644 .github/workflows/continuous-inspection.yml rename .github/workflows/{continuous-integration.yml => continuous-integration-51x.yml} (80%) delete mode 100644 .github/workflows/deploy-docs.yml delete mode 100644 .github/workflows/maven-central-release.yml delete mode 100644 .github/workflows/maven-central-stage.yml delete mode 100644 .github/workflows/release-notes-generation.yml diff --git a/.github/release-files-spec.json b/.github/release-files-spec.json deleted file mode 100644 index 66e9c681b5..0000000000 --- a/.github/release-files-spec.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "files": [ - { - "aql": { - "items.find": { - "$and": [ - { - "@build.name": "${buildname}", - "@build.number": "${buildnumber}", - "path": {"$match": "org*"} - }, - { - "$or": [ - { - "name": {"$match": "*.pom"} - }, - { - "name": {"$match": "*.jar"} - } - ] - } - ] - } - }, - "target": "nexus/" - } - ] -} \ No newline at end of file diff --git a/.github/workflows/artifactory-milestone-release.yml b/.github/workflows/artifactory-milestone-release.yml deleted file mode 100644 index 4c368a39a4..0000000000 --- a/.github/workflows/artifactory-milestone-release.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Artifactory Milestone Release - -on: - workflow_dispatch: - inputs: - releaseVersion: - description: "Milestone release version" - required: true - -jobs: - build: - name: Release milestone to Artifactory - runs-on: ubuntu-latest - steps: - - name: Checkout source code - uses: actions/checkout@v3 - - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'temurin' - cache: 'maven' - - - name: Capture release version - run: echo RELEASE_VERSION=${{ github.event.inputs.releaseVersion }} >> $GITHUB_ENV - - - name: Update release version - run: mvn versions:set -DgenerateBackupPoms=false -DnewVersion=$RELEASE_VERSION - - - name: Enforce release rules - run: mvn org.apache.maven.plugins:maven-enforcer-plugin:enforce -Drules=requireReleaseDeps - - - name: Build with Maven and deploy to Artifactory's milestone repository - env: - ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} - ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} - run: mvn -P artifactory-milestone -s settings.xml --batch-mode -Dmaven.test.skip=true deploy diff --git a/.github/workflows/artifactory-staging.yml b/.github/workflows/artifactory-staging.yml index ae8a04859c..86d1d98d34 100644 --- a/.github/workflows/artifactory-staging.yml +++ b/.github/workflows/artifactory-staging.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: releaseVersion: - description: "Release version" + description: "Release version (5.1.x)" required: true jobs: @@ -14,6 +14,8 @@ jobs: steps: - name: Checkout source code uses: actions/checkout@v3 + with: + ref: '5.1.x' - name: Set up JDK 17 uses: actions/setup-java@v3 diff --git a/.github/workflows/continuous-inspection.yml b/.github/workflows/continuous-inspection.yml deleted file mode 100644 index f496eba5c9..0000000000 --- a/.github/workflows/continuous-inspection.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Continuous inspection build - -on: - schedule: - - cron: '0 10 * * *' # Once per day at 10am UTC - workflow_dispatch: - -jobs: - code-quality-analysis: - name: code quality analysis report - runs-on: ubuntu-latest - steps: - - name: Checkout source code - uses: actions/checkout@v3 - - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'temurin' - cache: 'maven' - - - name: Analyse test coverage with Jacoco - run: mvn -P test-coverage verify - - - name: Analyse code quality with Sonar - if: github.repository == 'spring-projects/spring-batch' - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_URL }} - run: mvn sonar:sonar -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_TOKEN - diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration-51x.yml similarity index 80% rename from .github/workflows/continuous-integration.yml rename to .github/workflows/continuous-integration-51x.yml index b7100b84dc..1ca740a70d 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration-51x.yml @@ -1,16 +1,18 @@ -name: CI/CD build +name: CI/CD build for 5.1.x on: push: - branches: [ "main" ] + branches: [ "5.1.x" ] jobs: build: - name: Build branch + name: Build 5.1.x branch runs-on: ubuntu-latest steps: - name: Checkout source code uses: actions/checkout@v3 + with: + ref: '5.1.x' - name: Set up JDK 17 uses: actions/setup-java@v3 @@ -50,7 +52,8 @@ jobs: DOCS_HOST: ${{ secrets.DOCS_HOST }} DOCS_PATH: ${{ secrets.DOCS_PATH }} DOCS_USERNAME: ${{ secrets.DOCS_USERNAME }} - working-directory: spring-batch-docs + working-directory: spring-batch-docs/target run: | - cd target && unzip spring-batch-$PROJECT_VERSION-javadocs.zip - scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$PROJECT_VERSION + unzip spring-batch-$PROJECT_VERSION-javadocs.zip + ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST cd $DOCS_PATH && mkdir -p $PROJECT_VERSION/api + scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$PROJECT_VERSION/api diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml deleted file mode 100644 index 4af2314b75..0000000000 --- a/.github/workflows/deploy-docs.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Deploy Docs -on: - push: - branches-ignore: [ gh-pages ] - tags: '**' - repository_dispatch: - types: request-build-reference # legacy - workflow_dispatch: -permissions: - actions: write -jobs: - build: - runs-on: ubuntu-latest - if: github.repository_owner == 'spring-projects' - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - ref: docs-build - fetch-depth: 1 - - name: Dispatch (partial build) - if: github.ref_type == 'branch' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }} - - name: Dispatch (full build) - if: github.ref_type == 'tag' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) diff --git a/.github/workflows/documentation-upload.yml b/.github/workflows/documentation-upload.yml index 9f834e6deb..5eae40a13a 100644 --- a/.github/workflows/documentation-upload.yml +++ b/.github/workflows/documentation-upload.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: releaseVersion: - description: "Release version" + description: "Release version (5.1.x)" required: true jobs: @@ -17,6 +17,8 @@ jobs: - name: Checkout source code uses: actions/checkout@v3 + with: + ref: '5.1.x' - name: Set up JDK 17 uses: actions/setup-java@v3 @@ -55,8 +57,8 @@ jobs: working-directory: spring-batch-docs/target run: | unzip spring-batch-$RELEASE_VERSION-javadocs.zip - ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST cd $DOCS_PATH && mkdir -p $RELEASE_VERSION - scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$RELEASE_VERSION + ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST cd $DOCS_PATH && mkdir -p $RELEASE_VERSION/api + scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$RELEASE_VERSION/api unzip spring-batch-$RELEASE_VERSION-schemas.zip scp -i $HOME/.ssh/key batch/*.xsd $DOCS_USERNAME@$DOCS_HOST:$BATCH_SCHEMA_PATH diff --git a/.github/workflows/maven-central-release.yml b/.github/workflows/maven-central-release.yml deleted file mode 100644 index bce60ac9ea..0000000000 --- a/.github/workflows/maven-central-release.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Maven Central Release - -on: - workflow_dispatch: - inputs: - releaseVersion: - description: "Release version" - required: true - -jobs: - build: - runs-on: ubuntu-latest - steps: - - - name: Capture release version - run: echo RELEASE_VERSION=${{ github.event.inputs.releaseVersion }} >> $GITHUB_ENV - - - name: Prepare directory structure - run: | - mkdir -p nexus/org/springframework/batch/spring-batch-bom/$RELEASE_VERSION - mkdir -p nexus/org/springframework/batch/spring-batch-infrastructure/$RELEASE_VERSION - mkdir -p nexus/org/springframework/batch/spring-batch-core/$RELEASE_VERSION - mkdir -p nexus/org/springframework/batch/spring-batch-test/$RELEASE_VERSION - mkdir -p nexus/org/springframework/batch/spring-batch-integration/$RELEASE_VERSION - - - name: Download release files from Artifactory - env: - ARTIFACTORY_URL: "https://repo.spring.io/libs-staging-local/org/springframework/batch" - ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} - ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} - run: | - echo "Downloading BOM artifacts" - cd nexus/org/springframework/batch/spring-batch-bom/$RELEASE_VERSION - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-bom/$RELEASE_VERSION/spring-batch-bom-$RELEASE_VERSION.pom - - echo "Downloading infrastructure artifacts" - cd ../../../../../.. - cd nexus/org/springframework/batch/spring-batch-infrastructure/$RELEASE_VERSION - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-infrastructure/$RELEASE_VERSION/spring-batch-infrastructure-$RELEASE_VERSION.pom - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-infrastructure/$RELEASE_VERSION/spring-batch-infrastructure-$RELEASE_VERSION.jar - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-infrastructure/$RELEASE_VERSION/spring-batch-infrastructure-$RELEASE_VERSION-javadoc.jar - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-infrastructure/$RELEASE_VERSION/spring-batch-infrastructure-$RELEASE_VERSION-sources.jar - - echo "Downloading core artifacts" - cd ../../../../../.. - cd nexus/org/springframework/batch/spring-batch-core/$RELEASE_VERSION - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-core/$RELEASE_VERSION/spring-batch-core-$RELEASE_VERSION.pom - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-core/$RELEASE_VERSION/spring-batch-core-$RELEASE_VERSION.jar - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-core/$RELEASE_VERSION/spring-batch-core-$RELEASE_VERSION-javadoc.jar - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-core/$RELEASE_VERSION/spring-batch-core-$RELEASE_VERSION-sources.jar - - echo "Downloading test artifacts" - cd ../../../../../.. - cd nexus/org/springframework/batch/spring-batch-test/$RELEASE_VERSION - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-test/$RELEASE_VERSION/spring-batch-test-$RELEASE_VERSION.pom - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-test/$RELEASE_VERSION/spring-batch-test-$RELEASE_VERSION.jar - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-test/$RELEASE_VERSION/spring-batch-test-$RELEASE_VERSION-javadoc.jar - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-test/$RELEASE_VERSION/spring-batch-test-$RELEASE_VERSION-sources.jar - - echo "Downloading integration artifacts" - cd ../../../../../.. - cd nexus/org/springframework/batch/spring-batch-integration/$RELEASE_VERSION - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-integration/$RELEASE_VERSION/spring-batch-integration-$RELEASE_VERSION.pom - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-integration/$RELEASE_VERSION/spring-batch-integration-$RELEASE_VERSION.jar - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-integration/$RELEASE_VERSION/spring-batch-integration-$RELEASE_VERSION-javadoc.jar - wget --user="$ARTIFACTORY_USERNAME" --password="$ARTIFACTORY_PASSWORD" $ARTIFACTORY_URL/spring-batch-integration/$RELEASE_VERSION/spring-batch-integration-$RELEASE_VERSION-sources.jar - - - name: Sign artifacts and release them to Maven Central - uses: jvalkeal/nexus-sync@v0 - id: nexus - with: - url: ${{ secrets.OSSRH_URL }} - username: ${{ secrets.OSSRH_S01_TOKEN_USERNAME }} - password: ${{ secrets.OSSRH_S01_TOKEN_PASSWORD }} - staging-profile-name: ${{ secrets.OSSRH_STAGING_PROFILE_NAME }} - create: true - upload: true - close: true - release: true - generate-checksums: true - pgp-sign: true - pgp-sign-passphrase: ${{ secrets.GPG_PASSPHRASE }} - pgp-sign-private-key: ${{ secrets.GPG_PRIVATE_KEY }} diff --git a/.github/workflows/maven-central-stage.yml b/.github/workflows/maven-central-stage.yml deleted file mode 100644 index e01f26c54d..0000000000 --- a/.github/workflows/maven-central-stage.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Maven Central Staging - -on: - workflow_dispatch: - inputs: - buildName: - description: "Artifactory build name" - required: true - buildNumber: - description: "Artifactory build number" - required: true - -jobs: - build: - runs-on: ubuntu-latest - steps: - - # to get spec file in .github - - uses: actions/checkout@v2 - - # Setup jfrog cli - - uses: jfrog/setup-jfrog-cli@v1 - with: - version: 1.43.2 - env: - JF_ARTIFACTORY_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }} - - # Extract build id from input - - name: Extract Build Id - run: | - echo JFROG_CLI_BUILD_NAME=${{ github.event.inputs.buildName }} >> $GITHUB_ENV - echo JFROG_CLI_BUILD_NUMBER=${{ github.event.inputs.buildNumber }} >> $GITHUB_ENV - - # Download released files - - name: Download Release Files - run: | - jfrog rt download \ - --spec .github/release-files-spec.json \ - --spec-vars "buildname=$JFROG_CLI_BUILD_NAME;buildnumber=$JFROG_CLI_BUILD_NUMBER" - - # Create checksums, signatures and create staging repo on central and upload - - uses: jvalkeal/nexus-sync@v0 - id: nexus - with: - url: ${{ secrets.OSSRH_URL }} - username: ${{ secrets.OSSRH_S01_TOKEN_USERNAME }} - password: ${{ secrets.OSSRH_S01_TOKEN_PASSWORD }} - staging-profile-name: ${{ secrets.OSSRH_STAGING_PROFILE_NAME }} - create: true - upload: true - generate-checksums: true - pgp-sign: true - pgp-sign-passphrase: ${{ secrets.GPG_PASSPHRASE }} - pgp-sign-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - - # Print staging repo id - - name: Print Staging Repo Id - run: echo ${{ steps.nexus.outputs.staged-repository-id }} diff --git a/.github/workflows/release-notes-generation.yml b/.github/workflows/release-notes-generation.yml deleted file mode 100644 index fa601a05fa..0000000000 --- a/.github/workflows/release-notes-generation.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Generate Release notes - -on: - workflow_dispatch: - inputs: - milestoneNumber: - description: "Milestone title" - required: true - generatorVersion: - description: "Changelog Generator version" - required: true - -jobs: - build: - name: Generate release notes - runs-on: ubuntu-latest - steps: - - name: Capture milestone number and generator version - run: | - echo MILESTONE_NUMBER=${{ github.event.inputs.milestoneNumber }} >> $GITHUB_ENV - echo GENERATOR_VERSION=${{ github.event.inputs.generatorVersion }} >> $GITHUB_ENV - - - name: Download changelog generator - run: wget https://github.com/spring-io/github-changelog-generator/releases/download/v$GENERATOR_VERSION/github-changelog-generator.jar - - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'temurin' - - - name: Prepare configuration file - run: | - cat << EOF > application.yml - changelog: - repository: spring-projects/spring-batch - sections: - - title: ":star: New features" - labels: [ "type: feature" ] - - title: ":rocket: Enhancements" - labels: [ "type: enhancement" ] - - title: ":lady_beetle: Bug fixes" - labels: [ "type: bug" ] - - title: ":notebook_with_decorative_cover: Documentation" - labels: [ "in: documentation" ] - - title: ":hammer: Tasks" - labels: [ "type: task" ] - EOF - - - name: Generate release notes - run: java -jar github-changelog-generator.jar $MILESTONE_NUMBER release-notes.md - - - name: Print release notes - run: cat release-notes.md From 7922fccce097e01e224f7e1e6aee89a04fbecc62 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Mon, 22 Jan 2024 11:57:19 +0100 Subject: [PATCH 02/55] Upgrade Spring dependencies to latest snapshots --- pom.xml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index bf2ddf1a1b..6218881397 100644 --- a/pom.xml +++ b/pom.xml @@ -61,19 +61,19 @@ 17 - 6.1.0 - 2.0.4 - 6.2.0 - 1.12.0 + 6.1.4-SNAPSHOT + 2.0.5-SNAPSHOT + 6.2.2-SNAPSHOT + 1.12.3-SNAPSHOT - 3.2.0 - 3.2.0 - 3.2.0 - 4.2.0 - 3.1.0 - 3.1.0 - 3.2.0 + 3.2.3-SNAPSHOT + 3.2.3-SNAPSHOT + 3.2.3-SNAPSHOT + 4.2.3-SNAPSHOT + 3.1.2-SNAPSHOT + 3.1.2-SNAPSHOT + 3.2.2-SNAPSHOT 2.15.3 1.11.3 @@ -92,7 +92,7 @@ 3.0.2 - 1.2.0 + 1.2.3-SNAPSHOT 1.4.20 4.13.2 From 88484496d2eb34c910f66b18662de72b8078735a Mon Sep 17 00:00:00 2001 From: Alexander Afanasiev Date: Fri, 5 Jan 2024 10:51:15 +0100 Subject: [PATCH 03/55] Fix error message Issue #4528 --- .../batch/core/launch/support/JobOperatorFactoryBean.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobOperatorFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobOperatorFactoryBean.java index ce2ef8e4f2..a3c07375ec 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobOperatorFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobOperatorFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2022-2024 the original author 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 class JobOperatorFactoryBean implements FactoryBean, Initial public void afterPropertiesSet() throws Exception { Assert.notNull(this.transactionManager, "TransactionManager must not be null"); Assert.notNull(this.jobLauncher, "JobLauncher must not be null"); - Assert.notNull(this.jobRegistry, "JobLocator must not be null"); + Assert.notNull(this.jobRegistry, "JobRegistry must not be null"); Assert.notNull(this.jobExplorer, "JobExplorer must not be null"); Assert.notNull(this.jobRepository, "JobRepository must not be null"); if (this.transactionAttributeSource == null) { From 424756107313be5cf36ea6aee55267534fcf1b3a Mon Sep 17 00:00:00 2001 From: Henning Poettker Date: Mon, 18 Dec 2023 15:36:16 +0100 Subject: [PATCH 04/55] Add `JobRegistrySmartInitializingSingleton` (cherry picked from commit fe26d007440f2582f7a4e5e9672f29dc68cf6026) --- .../support/JobRegistryBeanPostProcessor.java | 6 +- ...JobRegistrySmartInitializingSingleton.java | 174 ++++++++++++++++++ ...gistrySmartInitializingSingletonTests.java | 116 ++++++++++++ ...text-with-smart-initializing-singleton.xml | 76 ++++++++ 4 files changed, 371 insertions(+), 1 deletion(-) create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingleton.java create mode 100644 spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingletonTests.java create mode 100644 spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/test-context-with-smart-initializing-singleton.xml diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistryBeanPostProcessor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistryBeanPostProcessor.java index 0670560c94..69ffe907e9 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistryBeanPostProcessor.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistryBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,10 @@ * {@link JobRegistry}. Include a bean of this type along with your job configuration and * use the same {@link JobRegistry} as a {@link JobLocator} when you need to locate a * {@link Job} to launch. + *

+ * An alternative to this class is {@link JobRegistrySmartInitializingSingleton}, which is + * recommended in cases where this class may cause early bean initializations. You must + * include at most one of either of them as a bean. * * @author Dave Syer * @author Mahmoud Ben Hassine diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingleton.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingleton.java new file mode 100644 index 0000000000..9e4bbb3a4f --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingleton.java @@ -0,0 +1,174 @@ +/* + * Copyright 2024 the original author 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.batch.core.configuration.support; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.configuration.DuplicateJobException; +import org.springframework.batch.core.configuration.JobLocator; +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.util.Assert; + +/** + * A {@link SmartInitializingSingleton} that registers {@link Job} beans with a + * {@link JobRegistry}. Include a bean of this type along with your job configuration and + * use the same {@link JobRegistry} as a {@link JobLocator} when you need to locate a + * {@link Job} to launch. + *

+ * This class is an alternative to {@link JobRegistryBeanPostProcessor} and prevents early + * bean initializations. You must include at most one of either of them as a bean. + * + * @author Henning Pöttker + * @since 5.1.1 + */ +public class JobRegistrySmartInitializingSingleton + implements SmartInitializingSingleton, BeanFactoryAware, InitializingBean, DisposableBean { + + private static final Log logger = LogFactory.getLog(JobRegistrySmartInitializingSingleton.class); + + // It doesn't make sense for this to have a default value... + private JobRegistry jobRegistry = null; + + private final Collection jobNames = new HashSet<>(); + + private String groupName = null; + + private ListableBeanFactory beanFactory; + + /** + * Default constructor. + */ + public JobRegistrySmartInitializingSingleton() { + } + + /** + * Convenience constructor for setting the {@link JobRegistry}. + * @param jobRegistry the {@link JobRegistry} to register the {@link Job}s with + */ + public JobRegistrySmartInitializingSingleton(JobRegistry jobRegistry) { + this.jobRegistry = jobRegistry; + } + + /** + * The group name for jobs registered by this component. Optional (defaults to null, + * which means that jobs are registered with their bean names). Useful where there is + * a hierarchy of application contexts all contributing to the same + * {@link JobRegistry}: child contexts can then define an instance with a unique group + * name to avoid clashes between job names. + * @param groupName the groupName to set + */ + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + /** + * Injection setter for {@link JobRegistry}. + * @param jobRegistry the {@link JobRegistry} to register the {@link Job}s with + */ + public void setJobRegistry(JobRegistry jobRegistry) { + this.jobRegistry = jobRegistry; + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + if (beanFactory instanceof ListableBeanFactory listableBeanFactory) { + this.beanFactory = listableBeanFactory; + } + } + + /** + * Make sure the registry is set before use. + */ + @Override + public void afterPropertiesSet() throws Exception { + Assert.state(jobRegistry != null, "JobRegistry must not be null"); + } + + /** + * Unregister all the {@link Job} instances that were registered by this post + * processor. + */ + @Override + public void destroy() throws Exception { + for (String name : jobNames) { + if (logger.isDebugEnabled()) { + logger.debug("Unregistering job: " + name); + } + jobRegistry.unregister(name); + } + jobNames.clear(); + } + + @Override + public void afterSingletonsInstantiated() { + if (beanFactory == null) { + return; + } + Map jobs = beanFactory.getBeansOfType(Job.class, false, false); + for (var entry : jobs.entrySet()) { + postProcessAfterInitialization(entry.getValue(), entry.getKey()); + } + } + + private void postProcessAfterInitialization(Job job, String beanName) { + try { + String groupName = this.groupName; + if (beanFactory instanceof DefaultListableBeanFactory defaultListableBeanFactory + && beanFactory.containsBean(beanName)) { + groupName = getGroupName(defaultListableBeanFactory.getBeanDefinition(beanName), job); + } + job = groupName == null ? job : new GroupAwareJob(groupName, job); + ReferenceJobFactory jobFactory = new ReferenceJobFactory(job); + String name = jobFactory.getJobName(); + if (logger.isDebugEnabled()) { + logger.debug("Registering job: " + name); + } + jobRegistry.register(jobFactory); + jobNames.add(name); + } + catch (DuplicateJobException e) { + throw new FatalBeanException("Cannot register job configuration", e); + } + } + + /** + * Determine a group name for the job to be registered. The default implementation + * returns the {@link #setGroupName(String) groupName} configured. Provides an + * extension point for specialised subclasses. + * @param beanDefinition the bean definition for the job + * @param job the job + * @return a group name for the job (or null if not needed) + */ + protected String getGroupName(BeanDefinition beanDefinition, Job job) { + return groupName; + } + +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingletonTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingletonTests.java new file mode 100644 index 0000000000..7738ee2d4f --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingletonTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2024 the original author 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.batch.core.configuration.support; + +import java.util.Collection; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.configuration.DuplicateJobException; +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.job.JobSupport; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; + +/** + * @author Henning Pöttker + */ +class JobRegistrySmartInitializingSingletonTests { + + private final JobRegistry jobRegistry = new MapJobRegistry(); + + private final JobRegistrySmartInitializingSingleton singleton = new JobRegistrySmartInitializingSingleton( + jobRegistry); + + private final ListableBeanFactory beanFactory = mock(ListableBeanFactory.class); + + @BeforeEach + void setUp() { + var job = new JobSupport(); + job.setName("foo"); + lenient().when(beanFactory.getBeansOfType(Job.class, false, false)).thenReturn(Map.of("bar", job)); + singleton.setBeanFactory(beanFactory); + } + + @Test + void testInitializationFails() { + singleton.setJobRegistry(null); + var exception = assertThrows(IllegalStateException.class, singleton::afterPropertiesSet); + assertTrue(exception.getMessage().contains("JobRegistry")); + } + + @Test + void testAfterSingletonsInstantiated() { + singleton.afterSingletonsInstantiated(); + assertEquals("[foo]", jobRegistry.getJobNames().toString()); + } + + @Test + void testAfterSingletonsInstantiatedWithGroupName() { + singleton.setGroupName("jobs"); + singleton.afterSingletonsInstantiated(); + assertEquals("[jobs.foo]", jobRegistry.getJobNames().toString()); + } + + @Test + void testAfterSingletonsInstantiatedWithDuplicate() { + singleton.afterSingletonsInstantiated(); + var exception = assertThrows(FatalBeanException.class, singleton::afterSingletonsInstantiated); + assertTrue(exception.getCause() instanceof DuplicateJobException); + } + + @Test + void testUnregisterOnDestroy() throws Exception { + singleton.afterSingletonsInstantiated(); + singleton.destroy(); + assertEquals("[]", jobRegistry.getJobNames().toString()); + } + + @Test + void testExecutionWithApplicationContext() throws Exception { + var context = new ClassPathXmlApplicationContext("test-context-with-smart-initializing-singleton.xml", + getClass()); + var registry = context.getBean("registry", JobRegistry.class); + Collection jobNames = registry.getJobNames(); + String[] names = context.getBeanNamesForType(JobSupport.class); + int count = names.length; + // Each concrete bean of type JobConfiguration is registered... + assertEquals(count, jobNames.size()); + // N.B. there is a failure / wonky mode where a parent bean is given an + // explicit name or beanName (using property setter): in this case then + // child beans will have the same name and will be re-registered (and + // override, if the registry supports that). + assertNotNull(registry.getJob("test-job")); + assertEquals(context.getBean("test-job-with-name"), registry.getJob("foo")); + assertEquals(context.getBean("test-job-with-bean-name"), registry.getJob("bar")); + assertEquals(context.getBean("test-job-with-parent-and-name"), registry.getJob("spam")); + assertEquals(context.getBean("test-job-with-parent-and-bean-name"), registry.getJob("bucket")); + assertEquals(context.getBean("test-job-with-concrete-parent"), registry.getJob("maps")); + assertEquals(context.getBean("test-job-with-concrete-parent-and-name"), registry.getJob("oof")); + assertEquals(context.getBean("test-job-with-concrete-parent-and-bean-name"), registry.getJob("rab")); + } + +} diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/test-context-with-smart-initializing-singleton.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/test-context-with-smart-initializing-singleton.xml new file mode 100644 index 0000000000..64ae6eed68 --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/test-context-with-smart-initializing-singleton.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 9ae45ae52e3fab1b9805d13ea03ac7e7f72f41aa Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Tue, 6 Feb 2024 15:21:47 +0100 Subject: [PATCH 05/55] Refine contribution #4521 - Update reference documentation - Minor test updates (cherry picked from commit d6b6361e597b51c9262c8c1c9a3b5bbdb894ed57) --- ...JobRegistrySmartInitializingSingleton.java | 4 +- ...gistrySmartInitializingSingletonTests.java | 16 +++++--- .../ROOT/pages/job/advanced-meta-data.adoc | 40 +++++++++++++++++-- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingleton.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingleton.java index 9e4bbb3a4f..ede418cf23 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingleton.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingleton.java @@ -113,8 +113,8 @@ public void afterPropertiesSet() throws Exception { } /** - * Unregister all the {@link Job} instances that were registered by this post - * processor. + * Unregister all the {@link Job} instances that were registered by this smart + * initializing singleton. */ @Override public void destroy() throws Exception { diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingletonTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingletonTests.java index 7738ee2d4f..f6db1e0187 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingletonTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/JobRegistrySmartInitializingSingletonTests.java @@ -29,6 +29,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -37,6 +38,7 @@ /** * @author Henning Pöttker + * @author Mahmoud Ben Hassine */ class JobRegistrySmartInitializingSingletonTests { @@ -59,34 +61,38 @@ void setUp() { void testInitializationFails() { singleton.setJobRegistry(null); var exception = assertThrows(IllegalStateException.class, singleton::afterPropertiesSet); - assertTrue(exception.getMessage().contains("JobRegistry")); + assertEquals("JobRegistry must not be null", exception.getMessage()); } @Test void testAfterSingletonsInstantiated() { singleton.afterSingletonsInstantiated(); - assertEquals("[foo]", jobRegistry.getJobNames().toString()); + Collection jobNames = jobRegistry.getJobNames(); + assertEquals(1, jobNames.size()); + assertEquals("foo", jobNames.iterator().next()); } @Test void testAfterSingletonsInstantiatedWithGroupName() { singleton.setGroupName("jobs"); singleton.afterSingletonsInstantiated(); - assertEquals("[jobs.foo]", jobRegistry.getJobNames().toString()); + Collection jobNames = jobRegistry.getJobNames(); + assertEquals(1, jobNames.size()); + assertEquals("jobs.foo", jobNames.iterator().next()); } @Test void testAfterSingletonsInstantiatedWithDuplicate() { singleton.afterSingletonsInstantiated(); var exception = assertThrows(FatalBeanException.class, singleton::afterSingletonsInstantiated); - assertTrue(exception.getCause() instanceof DuplicateJobException); + assertInstanceOf(DuplicateJobException.class, exception.getCause()); } @Test void testUnregisterOnDestroy() throws Exception { singleton.afterSingletonsInstantiated(); singleton.destroy(); - assertEquals("[]", jobRegistry.getJobNames().toString()); + assertTrue(jobRegistry.getJobNames().isEmpty()); } @Test diff --git a/spring-batch-docs/modules/ROOT/pages/job/advanced-meta-data.adoc b/spring-batch-docs/modules/ROOT/pages/job/advanced-meta-data.adoc index 94fc236f5c..bd41a5d941 100644 --- a/spring-batch-docs/modules/ROOT/pages/job/advanced-meta-data.adoc +++ b/spring-batch-docs/modules/ROOT/pages/job/advanced-meta-data.adoc @@ -173,9 +173,9 @@ The following example shows how to include a `JobRegistry` for a job defined in ==== -You can populate a `JobRegistry` in either of two ways: by using -a bean post processor or by using a registrar lifecycle component. The coming -sections describe these two mechanisms. +You can populate a `JobRegistry` in one of the following ways: by using +a bean post processor, or by using a smart initializing singleton or by using +a registrar lifecycle component. The coming sections describe these mechanisms. [[jobregistrybeanpostprocessor]] === JobRegistryBeanPostProcessor @@ -224,6 +224,40 @@ there to also be registered automatically. As of version 5.1, the `@EnableBatchProcessing` annotation automatically registers a `jobRegistryBeanPostProcessor` bean in the application context. +[[jobregistrysmartinitializingsingleton]] +=== JobRegistrySmartInitializingSingleton + +This is a `SmartInitializingSingleton` that registers all singleton jobs within the job registry. + +[tabs] +==== +Java:: ++ +The following example shows how to define a `JobRegistrySmartInitializingSingleton` in Java: ++ +.Java Configuration +[source, java] +---- +@Bean +public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton(JobRegistry jobRegistry) { + return new JobRegistrySmartInitializingSingleton(jobRegistry); +} +---- + +XML:: ++ +The following example shows how to define a `JobRegistrySmartInitializingSingleton` in XML: ++ +.XML Configuration +[source, xml] +---- + + + +---- + +==== + [[automaticjobregistrar]] === AutomaticJobRegistrar From 0af714d1dd9860c109eaba4ac53e9e0d5e84aa60 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Fri, 9 Feb 2024 10:16:25 +0100 Subject: [PATCH 06/55] Update antora-extensions to v1.8.2 Issue #4534 --- spring-batch-docs/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index 6c338c613d..982d561ffb 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -26,7 +26,7 @@ @antora/atlas-extension@1.0.0-alpha.1 @antora/collector-extension@1.0.0-alpha.3 @asciidoctor/tabs@1.0.0-beta.3 - @springio/antora-extensions@1.7.0 + @springio/antora-extensions@1.8.2 @springio/asciidoctor-extensions@1.0.0-alpha.9 From fce780fdc04776ed62d0cf528e27367277a3afe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B8rge=20Andersen?= Date: Fri, 5 Jan 2024 16:45:10 +0100 Subject: [PATCH 07/55] Fix javadoc referencing Long when it should be Double Resolves #4526 --- .../main/java/org/springframework/batch/core/JobParameters.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java index 36cc3a1d44..8f001e84c7 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java @@ -141,7 +141,7 @@ public String getString(String key, @Nullable String defaultValue) { } /** - * Typesafe getter for the {@link Long} represented by the provided key. + * Typesafe getter for the {@link Double} represented by the provided key. * @param key The key for which to get a value. * @return The {@link Double} value or {@code null} if the key is absent. */ From 85a84cb30f16e74b19bd1e631315e708523396ec Mon Sep 17 00:00:00 2001 From: Henning Poettker Date: Thu, 30 Nov 2023 10:43:00 +0100 Subject: [PATCH 08/55] Check dirty flag of step execution context before update in inner loop --- .../springframework/batch/core/step/tasklet/TaskletStep.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/TaskletStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/TaskletStep.java index b4ede49ed4..446daf7490 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/TaskletStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/TaskletStep.java @@ -430,7 +430,9 @@ public RepeatStatus doInTransaction(TransactionStatus status) { try { // Going to attempt a commit. If it fails this flag will // stay false and we can use that later. - getJobRepository().updateExecutionContext(stepExecution); + if (stepExecution.getExecutionContext().isDirty()) { + getJobRepository().updateExecutionContext(stepExecution); + } stepExecution.incrementCommitCount(); if (logger.isDebugEnabled()) { logger.debug("Saving step execution before commit: " + stepExecution); From 964df6d643705d2b5448a997d2fbb699c4eb59a2 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 14 Feb 2024 15:01:59 +0100 Subject: [PATCH 09/55] Fix exception when parsing empty values in DefaultJobParametersConverter Resolves #4505 --- .../DefaultJobParametersConverter.java | 8 ++++++-- .../DefaultJobParametersConverterTests.java | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/converter/DefaultJobParametersConverter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/converter/DefaultJobParametersConverter.java index 522175f62c..a9f671ca56 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/converter/DefaultJobParametersConverter.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/converter/DefaultJobParametersConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -169,7 +169,11 @@ protected JobParameter decode(String encodedJobParameter) { } private String parseValue(String encodedJobParameter) { - return StringUtils.commaDelimitedListToStringArray(encodedJobParameter)[0]; + String[] tokens = StringUtils.commaDelimitedListToStringArray(encodedJobParameter); + if (tokens.length == 0) { + return ""; + } + return tokens[0]; } private Class parseType(String encodedJobParameter) { diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java index e413162a41..d39b9ad5eb 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test; +import org.springframework.batch.core.JobParameter; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; import org.springframework.util.StringUtils; @@ -129,6 +130,22 @@ void testGetParametersWithBogusLong() { } } + @Test + void testGetParametersWithEmptyValue() { + // given + String[] args = new String[] { "parameter=" }; + + // when + JobParameters jobParameters = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "=")); + + // then + assertEquals(1, jobParameters.getParameters().size()); + JobParameter parameter = jobParameters.getParameters().get("parameter"); + assertEquals("", parameter.getValue()); + assertEquals(String.class, parameter.getType()); + assertTrue(parameter.isIdentifying()); + } + @Test void testGetParametersWithDoubleValueDeclaredAsLong() { From b98d1b148245942b568381c9596d59d61118dacb Mon Sep 17 00:00:00 2001 From: Henning Poettker Date: Tue, 21 Nov 2023 23:31:13 +0100 Subject: [PATCH 10/55] Let SimpleJobRepository#deleteJobInstance delete corresponding step executions Resolves #4382 --- .../support/SimpleJobRepository.java | 4 +- .../SimpleJobRepositoryIntegrationTests.java | 63 ++++++++----------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java index 44f8bf6eca..e98752c987 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -328,7 +328,7 @@ public void deleteJobExecution(JobExecution jobExecution) { @Override public void deleteJobInstance(JobInstance jobInstance) { - List jobExecutions = this.jobExecutionDao.findJobExecutions(jobInstance); + List jobExecutions = findJobExecutions(jobInstance); for (JobExecution jobExecution : jobExecutions) { deleteJobExecution(jobExecution); } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/support/SimpleJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/support/SimpleJobRepositoryIntegrationTests.java index 53c33b178e..eb81dbd246 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/support/SimpleJobRepositoryIntegrationTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/support/SimpleJobRepositoryIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2022 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,12 +32,13 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; -import java.util.Arrays; +import java.util.List; +import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.fail; /** * Repository tests using JDBC DAOs (rather than mocks). @@ -152,11 +153,7 @@ void testGetStepExecutionCountAndLastStepExecution() throws Exception { @Transactional @Test void testSaveExecutionContext() throws Exception { - ExecutionContext ctx = new ExecutionContext() { - { - putLong("crashedPosition", 7); - } - }; + ExecutionContext ctx = new ExecutionContext(Map.of("crashedPosition", 7)); JobExecution jobExec = jobRepository.createJobExecution(job.getName(), jobParameters); jobExec.setStartTime(LocalDateTime.now()); jobExec.setExecutionContext(ctx); @@ -169,11 +166,6 @@ void testSaveExecutionContext() throws Exception { StepExecution retrievedStepExec = jobRepository.getLastStepExecution(jobExec.getJobInstance(), step.getName()); assertEquals(stepExec, retrievedStepExec); assertEquals(ctx, retrievedStepExec.getExecutionContext()); - - // JobExecution retrievedJobExec = - // jobRepository.getLastJobExecution(jobExec.getJobInstance()); - // assertEquals(jobExec, retrievedJobExec); - // assertEquals(ctx, retrievedJobExec.getExecutionContext()); } /* @@ -205,7 +197,7 @@ void testGetLastJobExecution() throws Exception { jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters); StepExecution stepExecution = new StepExecution("step1", jobExecution); jobRepository.add(stepExecution); - jobExecution.addStepExecutions(Arrays.asList(stepExecution)); + jobExecution.addStepExecutions(List.of(stepExecution)); assertEquals(jobExecution, jobRepository.getLastJobExecution(job.getName(), jobParameters)); assertEquals(stepExecution, jobExecution.getStepExecutions().iterator().next()); } @@ -233,42 +225,41 @@ void testReExecuteWithSameJobParameters() throws Exception { */ @Transactional @Test - public void testReExecuteWithSameJobParametersWhenRunning() throws Exception { + void testReExecuteWithSameJobParametersWhenRunning() throws Exception { JobParameters jobParameters = new JobParametersBuilder().addString("stringKey", "stringValue") .toJobParameters(); // jobExecution with status STARTING JobExecution jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters); - try { - jobRepository.createJobExecution(job.getName(), jobParameters); - fail(); - } - catch (JobExecutionAlreadyRunningException e) { - // expected - } + assertThrows(JobExecutionAlreadyRunningException.class, + () -> jobRepository.createJobExecution(job.getName(), jobParameters)); // jobExecution with status STARTED jobExecution.setStatus(BatchStatus.STARTED); jobExecution.setStartTime(LocalDateTime.now()); jobRepository.update(jobExecution); - try { - jobRepository.createJobExecution(job.getName(), jobParameters); - fail(); - } - catch (JobExecutionAlreadyRunningException e) { - // expected - } + assertThrows(JobExecutionAlreadyRunningException.class, + () -> jobRepository.createJobExecution(job.getName(), jobParameters)); // jobExecution with status STOPPING jobExecution.setStatus(BatchStatus.STOPPING); jobRepository.update(jobExecution); - try { - jobRepository.createJobExecution(job.getName(), jobParameters); - fail(); - } - catch (JobExecutionAlreadyRunningException e) { - // expected - } + assertThrows(JobExecutionAlreadyRunningException.class, + () -> jobRepository.createJobExecution(job.getName(), jobParameters)); + } + + @Transactional + @Test + void testDeleteJobInstance() throws Exception { + var jobParameters = new JobParametersBuilder().addString("foo", "bar").toJobParameters(); + var jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters); + var stepExecution = new StepExecution("step", jobExecution); + jobRepository.add(stepExecution); + + jobRepository.deleteJobInstance(jobExecution.getJobInstance()); + + assertEquals(0, jobRepository.findJobInstancesByName(job.getName(), 0, 1).size()); + assertNull(jobRepository.getLastJobExecution(job.getName(), jobParameters)); } } From 3c46ab86cdd0962a7172ded569f02cebd3141be8 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Mon, 19 Feb 2024 14:16:43 +0100 Subject: [PATCH 11/55] Fix deprecations in MongoPagingItemReader Resolves #4552 --- .../item/data/MongoPagingItemReader.java | 73 ++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/MongoPagingItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/MongoPagingItemReader.java index 442d6956e2..5c2278cacc 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/MongoPagingItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/MongoPagingItemReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,14 @@ */ package org.springframework.batch.item.data; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.item.ItemReader; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.query.Query; import org.springframework.util.ClassUtils; @@ -70,4 +76,69 @@ public MongoPagingItemReader() { setName(ClassUtils.getShortName(MongoPagingItemReader.class)); } + @Override + public void setTemplate(MongoOperations template) { + super.setTemplate(template); + } + + @Override + public void setQuery(Query query) { + super.setQuery(query); + } + + @Override + public void setQuery(String queryString) { + super.setQuery(queryString); + } + + @Override + public void setTargetType(Class type) { + super.setTargetType(type); + } + + @Override + public void setParameterValues(List parameterValues) { + super.setParameterValues(parameterValues); + } + + @Override + public void setFields(String fields) { + super.setFields(fields); + } + + @Override + public void setSort(Map sorts) { + super.setSort(sorts); + } + + @Override + public void setCollection(String collection) { + super.setCollection(collection); + } + + @Override + public void setHint(String hint) { + super.setHint(hint); + } + + @Override + public void afterPropertiesSet() throws Exception { + super.afterPropertiesSet(); + } + + @Override + protected Iterator doPageRead() { + return super.doPageRead(); + } + + @Override + protected String replacePlaceholders(String input, List values) { + return super.replacePlaceholders(input, values); + } + + @Override + protected Sort convertToSort(Map sorts) { + return super.convertToSort(sorts); + } + } From d2fa9fe83185cde6c763331c78e0853b868ebdaf Mon Sep 17 00:00:00 2001 From: Ilpyo-Yang Date: Mon, 23 Oct 2023 23:32:12 +0900 Subject: [PATCH 12/55] Add AbstractTaskletStepBuilder copy constructor This commit includes tests for the copy constructor of AbstractTaskletStepBuilder and for the faultTolerant method, specifically after taskExecutor has been set. (cherry picked from commit b9ba8ffb861119924cbb4e17069ddd9e911aaa91) --- .../builder/AbstractTaskletStepBuilder.java | 18 +++ .../core/step/builder/SimpleStepBuilder.java | 1 - .../test/AbstractTaskletStepBuilderTests.java | 114 ++++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 spring-batch-test/src/test/java/org/springframework/batch/test/AbstractTaskletStepBuilderTests.java diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/AbstractTaskletStepBuilder.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/AbstractTaskletStepBuilder.java index 05d9f13906..36ce5918a6 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/AbstractTaskletStepBuilder.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/AbstractTaskletStepBuilder.java @@ -49,6 +49,7 @@ * @author Dave Syer * @author Michael Minella * @author Mahmoud Ben Hassine + * @author Ilpyo Yang * @since 2.2 * @param the type of builder represented */ @@ -74,6 +75,23 @@ public AbstractTaskletStepBuilder(StepBuilderHelper parent) { super(parent); } + /** + * Create a new builder initialized with any properties in the parent. The parent is + * copied, so it can be re-used. + * @param parent a parent helper containing common step properties + */ + public AbstractTaskletStepBuilder(AbstractTaskletStepBuilder parent) { + super(parent); + this.chunkListeners = parent.chunkListeners; + this.stepOperations = parent.stepOperations; + this.transactionManager = parent.transactionManager; + this.transactionAttribute = parent.transactionAttribute; + this.streams.addAll(parent.streams); + this.exceptionHandler = parent.exceptionHandler; + this.throttleLimit = parent.throttleLimit; + this.taskExecutor = parent.taskExecutor; + } + protected abstract Tasklet createTasklet(); /** diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/SimpleStepBuilder.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/SimpleStepBuilder.java index aa51c34e54..088b17ca5f 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/SimpleStepBuilder.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/SimpleStepBuilder.java @@ -114,7 +114,6 @@ protected SimpleStepBuilder(SimpleStepBuilder parent) { this.itemListeners = parent.itemListeners; this.readerTransactionalQueue = parent.readerTransactionalQueue; this.meterRegistry = parent.meterRegistry; - this.transactionManager(parent.getTransactionManager()); } public FaultTolerantStepBuilder faultTolerant() { diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/AbstractTaskletStepBuilderTests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/AbstractTaskletStepBuilderTests.java new file mode 100644 index 0000000000..465d6f5f5b --- /dev/null +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/AbstractTaskletStepBuilderTests.java @@ -0,0 +1,114 @@ +package org.springframework.batch.test; +/* + * Copyright 2020-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.AbstractTaskletStepBuilder; +import org.springframework.batch.core.step.builder.SimpleStepBuilder; +import org.springframework.batch.core.step.builder.StepBuilderHelper; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.test.context.SpringBatchTest; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.TaskExecutor; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +/** + * Test cases for verifying the {@link AbstractTaskletStepBuilder} and faultTolerant() functionality. + * + * @author Ilpyo Yang + */ +@SpringBatchTest +@SpringJUnitConfig +public class AbstractTaskletStepBuilderTests { + private final JobRepository jobRepository = mock(JobRepository.class); + private final int chunkSize = 10; + private final ItemReader itemReader = mock(ItemReader.class); + private final ItemProcessor itemProcessor = mock(ItemProcessor.class); + private final ItemWriter itemWriter = mock(ItemWriter.class); + private final SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); + SimpleStepBuilder simpleStepBuilder; + + private T accessPrivateField(Object o, String fieldName) throws ReflectiveOperationException { + Field field = o.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + return (T) field.get(o); + } + + private T accessSuperClassPrivateField(Object o, String fieldName) throws ReflectiveOperationException { + Field field = o.getClass().getSuperclass().getDeclaredField(fieldName); + field.setAccessible(true); + return (T) field.get(o); + } + + @BeforeEach + void set(){ + StepBuilderHelper stepBuilderHelper = new StepBuilderHelper("test", jobRepository) { + @Override + protected StepBuilderHelper self() { + return null; + } + }; + simpleStepBuilder = new SimpleStepBuilder(stepBuilderHelper); + simpleStepBuilder.chunk(chunkSize); + simpleStepBuilder.reader(itemReader); + simpleStepBuilder.processor(itemProcessor); + simpleStepBuilder.writer(itemWriter); + } + + @Test + void copyConstractorTest() throws ReflectiveOperationException { + Constructor constructor = SimpleStepBuilder.class.getDeclaredConstructor(SimpleStepBuilder.class); + constructor.setAccessible(true); + SimpleStepBuilder copySimpleStepBuilder = constructor.newInstance(simpleStepBuilder); + + int copyChunkSize = accessPrivateField(copySimpleStepBuilder, "chunkSize"); + ItemReader copyItemReader = accessPrivateField(copySimpleStepBuilder, "reader"); + ItemProcessor copyItemProcessor = accessPrivateField(copySimpleStepBuilder, "processor"); + ItemWriter copyItemWriter = accessPrivateField(copySimpleStepBuilder, "writer"); + + assertEquals(chunkSize, copyChunkSize); + assertEquals(itemReader, copyItemReader); + assertEquals(itemProcessor, copyItemProcessor); + assertEquals(itemWriter, copyItemWriter); + } + + @Test + void faultTolerantMethodTest() throws ReflectiveOperationException { + simpleStepBuilder.taskExecutor(taskExecutor); // The task executor is set before faultTolerant() + simpleStepBuilder.faultTolerant(); + + int afterChunkSize = accessPrivateField(simpleStepBuilder, "chunkSize"); + ItemReader afterItemReader = accessPrivateField(simpleStepBuilder, "reader"); + ItemProcessor afterItemProcessor = accessPrivateField(simpleStepBuilder, "processor"); + ItemWriter afterItemWriter = accessPrivateField(simpleStepBuilder, "writer"); + TaskExecutor afterTaskExecutor = accessSuperClassPrivateField(simpleStepBuilder, "taskExecutor"); + + assertEquals(chunkSize, afterChunkSize); + assertEquals(itemReader, afterItemReader); + assertEquals(itemProcessor, afterItemProcessor); + assertEquals(itemWriter, afterItemWriter); + assertEquals(taskExecutor, afterTaskExecutor); + } +} From f53ef73cfa5747bb34f77c0debc97c28c20f1005 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Mon, 19 Feb 2024 15:23:50 +0100 Subject: [PATCH 13/55] Refine contribution #4471 - Update tests - Move test class to the core module (cherry picked from commit 4b8e504972a59a99e33e634a12c6ceebbad5fca8) --- .../AbstractTaskletStepBuilderTests.java | 88 ++++++++++++++ .../test/AbstractTaskletStepBuilderTests.java | 114 ------------------ 2 files changed, 88 insertions(+), 114 deletions(-) create mode 100644 spring-batch-core/src/test/java/org/springframework/batch/core/step/builder/AbstractTaskletStepBuilderTests.java delete mode 100644 spring-batch-test/src/test/java/org/springframework/batch/test/AbstractTaskletStepBuilderTests.java diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/builder/AbstractTaskletStepBuilderTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/builder/AbstractTaskletStepBuilderTests.java new file mode 100644 index 0000000000..6cd6f2374e --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/builder/AbstractTaskletStepBuilderTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2024 the original author 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.batch.core.step.builder; + +import org.junit.jupiter.api.Test; + +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.tasklet.TaskletStep; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.repeat.support.TaskExecutorRepeatTemplate; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.transaction.PlatformTransactionManager; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.mockito.Mockito.mock; + +/** + * Test cases for verifying the {@link AbstractTaskletStepBuilder} and faultTolerant() + * functionality. + * + * Issue: https://github.com/spring-projects/spring-batch/issues/4438 + * + * @author Ilpyo Yang + * @author Mahmoud Ben Hassine + */ +public class AbstractTaskletStepBuilderTests { + + private final JobRepository jobRepository = mock(JobRepository.class); + + private final PlatformTransactionManager transactionManager = mock(PlatformTransactionManager.class); + + private final int chunkSize = 10; + + private final ItemReader itemReader = mock(ItemReader.class); + + private final ItemProcessor itemProcessor = mock(ItemProcessor.class); + + private final ItemWriter itemWriter = mock(ItemWriter.class); + + private final SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); + + @Test + void testSetTaskExecutorBeforeFaultTolerant() { + TaskletStep step = new StepBuilder("step-name", jobRepository) + .chunk(chunkSize, transactionManager) + .taskExecutor(taskExecutor) + .reader(itemReader) + .processor(itemProcessor) + .writer(itemWriter) + .faultTolerant() + .build(); + + Object stepOperations = ReflectionTestUtils.getField(step, "stepOperations"); + assertInstanceOf(TaskExecutorRepeatTemplate.class, stepOperations); + } + + @Test + void testSetTaskExecutorAfterFaultTolerant() { + TaskletStep step = new StepBuilder("step-name", jobRepository) + .chunk(chunkSize, transactionManager) + .reader(itemReader) + .processor(itemProcessor) + .writer(itemWriter) + .faultTolerant() + .taskExecutor(taskExecutor) + .build(); + + Object stepOperations = ReflectionTestUtils.getField(step, "stepOperations"); + assertInstanceOf(TaskExecutorRepeatTemplate.class, stepOperations); + } + +} diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/AbstractTaskletStepBuilderTests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/AbstractTaskletStepBuilderTests.java deleted file mode 100644 index 465d6f5f5b..0000000000 --- a/spring-batch-test/src/test/java/org/springframework/batch/test/AbstractTaskletStepBuilderTests.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.springframework.batch.test; -/* - * Copyright 2020-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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. - */ - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.step.builder.AbstractTaskletStepBuilder; -import org.springframework.batch.core.step.builder.SimpleStepBuilder; -import org.springframework.batch.core.step.builder.StepBuilderHelper; -import org.springframework.batch.item.ItemProcessor; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ItemWriter; -import org.springframework.batch.test.context.SpringBatchTest; -import org.springframework.core.task.SimpleAsyncTaskExecutor; -import org.springframework.core.task.TaskExecutor; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -/** - * Test cases for verifying the {@link AbstractTaskletStepBuilder} and faultTolerant() functionality. - * - * @author Ilpyo Yang - */ -@SpringBatchTest -@SpringJUnitConfig -public class AbstractTaskletStepBuilderTests { - private final JobRepository jobRepository = mock(JobRepository.class); - private final int chunkSize = 10; - private final ItemReader itemReader = mock(ItemReader.class); - private final ItemProcessor itemProcessor = mock(ItemProcessor.class); - private final ItemWriter itemWriter = mock(ItemWriter.class); - private final SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); - SimpleStepBuilder simpleStepBuilder; - - private T accessPrivateField(Object o, String fieldName) throws ReflectiveOperationException { - Field field = o.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - return (T) field.get(o); - } - - private T accessSuperClassPrivateField(Object o, String fieldName) throws ReflectiveOperationException { - Field field = o.getClass().getSuperclass().getDeclaredField(fieldName); - field.setAccessible(true); - return (T) field.get(o); - } - - @BeforeEach - void set(){ - StepBuilderHelper stepBuilderHelper = new StepBuilderHelper("test", jobRepository) { - @Override - protected StepBuilderHelper self() { - return null; - } - }; - simpleStepBuilder = new SimpleStepBuilder(stepBuilderHelper); - simpleStepBuilder.chunk(chunkSize); - simpleStepBuilder.reader(itemReader); - simpleStepBuilder.processor(itemProcessor); - simpleStepBuilder.writer(itemWriter); - } - - @Test - void copyConstractorTest() throws ReflectiveOperationException { - Constructor constructor = SimpleStepBuilder.class.getDeclaredConstructor(SimpleStepBuilder.class); - constructor.setAccessible(true); - SimpleStepBuilder copySimpleStepBuilder = constructor.newInstance(simpleStepBuilder); - - int copyChunkSize = accessPrivateField(copySimpleStepBuilder, "chunkSize"); - ItemReader copyItemReader = accessPrivateField(copySimpleStepBuilder, "reader"); - ItemProcessor copyItemProcessor = accessPrivateField(copySimpleStepBuilder, "processor"); - ItemWriter copyItemWriter = accessPrivateField(copySimpleStepBuilder, "writer"); - - assertEquals(chunkSize, copyChunkSize); - assertEquals(itemReader, copyItemReader); - assertEquals(itemProcessor, copyItemProcessor); - assertEquals(itemWriter, copyItemWriter); - } - - @Test - void faultTolerantMethodTest() throws ReflectiveOperationException { - simpleStepBuilder.taskExecutor(taskExecutor); // The task executor is set before faultTolerant() - simpleStepBuilder.faultTolerant(); - - int afterChunkSize = accessPrivateField(simpleStepBuilder, "chunkSize"); - ItemReader afterItemReader = accessPrivateField(simpleStepBuilder, "reader"); - ItemProcessor afterItemProcessor = accessPrivateField(simpleStepBuilder, "processor"); - ItemWriter afterItemWriter = accessPrivateField(simpleStepBuilder, "writer"); - TaskExecutor afterTaskExecutor = accessSuperClassPrivateField(simpleStepBuilder, "taskExecutor"); - - assertEquals(chunkSize, afterChunkSize); - assertEquals(itemReader, afterItemReader); - assertEquals(itemProcessor, afterItemProcessor); - assertEquals(itemWriter, afterItemWriter); - assertEquals(taskExecutor, afterTaskExecutor); - } -} From d73b9a8ee9d4e727d01265848edeff0f173b8229 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 21 Feb 2024 16:40:27 +0100 Subject: [PATCH 14/55] Prepare release 5.1.1 --- pom.xml | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/pom.xml b/pom.xml index 6218881397..fcf3aebf0b 100644 --- a/pom.xml +++ b/pom.xml @@ -61,57 +61,57 @@ 17 - 6.1.4-SNAPSHOT - 2.0.5-SNAPSHOT - 6.2.2-SNAPSHOT - 1.12.3-SNAPSHOT + 6.1.4 + 2.0.5 + 6.2.2 + 1.12.3 - 3.2.3-SNAPSHOT - 3.2.3-SNAPSHOT - 3.2.3-SNAPSHOT - 4.2.3-SNAPSHOT - 3.1.2-SNAPSHOT - 3.1.2-SNAPSHOT - 3.2.2-SNAPSHOT + 3.2.3 + 3.2.3 + 3.2.3 + 4.2.3 + 3.1.2 + 3.1.2 + 3.2.2 - 2.15.3 + 2.15.4 1.11.3 2.10.1 - 6.3.1.Final + 6.3.2.Final 2.1.1 2.1.2 3.1.0 3.0.2 3.1.0 - 4.0.8 + 4.0.9 4.11.1 - 5.10.1 + 5.10.2 3.0.2 - 1.2.3-SNAPSHOT + 1.2.3 1.4.20 4.13.2 ${junit-jupiter.version} 2.2 - 3.24.2 - 5.7.0 + 3.25.3 + 5.10.0 2.9.1 - 2.15.0 + 2.15.1 2.11.0 - 2.0.9 + 2.0.12 2.7.2 2.2.224 - 3.44.0.0 + 3.45.1.0 10.16.1.1 2.18.13 2.31.2 4.0.4 - 2.22.0 + 2.22.1 8.0.1.Final 5.0.1 4.0.2 @@ -119,15 +119,15 @@ 4.0.1 2.0.2 6.5.1 - 1.9.20.1 - 8.2.0 - 3.3.0 - 42.7.0 + 1.9.21.1 + 8.3.0 + 3.3.2 + 42.7.2 11.5.8.0 - 19.21.0.0 + 19.22.0.0 11.2.3.jre17 1.3.1 - 1.19.3 + 1.19.5 1.5.1 From 1b6b792432369b860a281ec7382c8731c9aba9ed Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 21 Feb 2024 17:04:00 +0100 Subject: [PATCH 15/55] Release version 5.1.1 --- pom.xml | 2 +- spring-batch-bom/pom.xml | 2 +- spring-batch-core/pom.xml | 2 +- spring-batch-docs/pom.xml | 2 +- spring-batch-infrastructure/pom.xml | 2 +- spring-batch-integration/pom.xml | 2 +- spring-batch-samples/pom.xml | 2 +- spring-batch-test/pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index fcf3aebf0b..308eb3901a 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ designed to enable the development of robust batch applications vital for the daily operations of enterprise systems. Spring Batch is part of the Spring Portfolio. - 5.1.1-SNAPSHOT + 5.1.1 pom https://projects.spring.io/spring-batch diff --git a/spring-batch-bom/pom.xml b/spring-batch-bom/pom.xml index a79875a89d..de4fc06b80 100644 --- a/spring-batch-bom/pom.xml +++ b/spring-batch-bom/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1-SNAPSHOT + 5.1.1 spring-batch-bom pom diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index 62b15ce662..1e804ab72c 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1-SNAPSHOT + 5.1.1 spring-batch-core jar diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index 982d561ffb..c6475ce1a9 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1-SNAPSHOT + 5.1.1 spring-batch-docs Spring Batch Docs diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml index 4658581ac3..db37449fac 100644 --- a/spring-batch-infrastructure/pom.xml +++ b/spring-batch-infrastructure/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1-SNAPSHOT + 5.1.1 spring-batch-infrastructure jar diff --git a/spring-batch-integration/pom.xml b/spring-batch-integration/pom.xml index 0b873c390a..cca5ad66bf 100644 --- a/spring-batch-integration/pom.xml +++ b/spring-batch-integration/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1-SNAPSHOT + 5.1.1 spring-batch-integration Spring Batch Integration diff --git a/spring-batch-samples/pom.xml b/spring-batch-samples/pom.xml index 6d4c70160f..4986a4a7b0 100644 --- a/spring-batch-samples/pom.xml +++ b/spring-batch-samples/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1-SNAPSHOT + 5.1.1 spring-batch-samples jar diff --git a/spring-batch-test/pom.xml b/spring-batch-test/pom.xml index 00b6c644f5..5f2832ae4a 100644 --- a/spring-batch-test/pom.xml +++ b/spring-batch-test/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1-SNAPSHOT + 5.1.1 spring-batch-test Spring Batch Test From bfe7f38e4f1455c861f48502d845b4b5abf81c5e Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 21 Feb 2024 17:04:13 +0100 Subject: [PATCH 16/55] Next development version --- pom.xml | 2 +- spring-batch-bom/pom.xml | 2 +- spring-batch-core/pom.xml | 2 +- spring-batch-docs/pom.xml | 2 +- spring-batch-infrastructure/pom.xml | 2 +- spring-batch-integration/pom.xml | 2 +- spring-batch-samples/pom.xml | 2 +- spring-batch-test/pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 308eb3901a..c1652dde92 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ designed to enable the development of robust batch applications vital for the daily operations of enterprise systems. Spring Batch is part of the Spring Portfolio. - 5.1.1 + 5.1.2-SNAPSHOT pom https://projects.spring.io/spring-batch diff --git a/spring-batch-bom/pom.xml b/spring-batch-bom/pom.xml index de4fc06b80..ddc89539f0 100644 --- a/spring-batch-bom/pom.xml +++ b/spring-batch-bom/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1 + 5.1.2-SNAPSHOT spring-batch-bom pom diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index 1e804ab72c..233ca61cd0 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1 + 5.1.2-SNAPSHOT spring-batch-core jar diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index c6475ce1a9..852cc9c831 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1 + 5.1.2-SNAPSHOT spring-batch-docs Spring Batch Docs diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml index db37449fac..4da5ddb10a 100644 --- a/spring-batch-infrastructure/pom.xml +++ b/spring-batch-infrastructure/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1 + 5.1.2-SNAPSHOT spring-batch-infrastructure jar diff --git a/spring-batch-integration/pom.xml b/spring-batch-integration/pom.xml index cca5ad66bf..a193782dfb 100644 --- a/spring-batch-integration/pom.xml +++ b/spring-batch-integration/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1 + 5.1.2-SNAPSHOT spring-batch-integration Spring Batch Integration diff --git a/spring-batch-samples/pom.xml b/spring-batch-samples/pom.xml index 4986a4a7b0..27aea6dee7 100644 --- a/spring-batch-samples/pom.xml +++ b/spring-batch-samples/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1 + 5.1.2-SNAPSHOT spring-batch-samples jar diff --git a/spring-batch-test/pom.xml b/spring-batch-test/pom.xml index 5f2832ae4a..982ccadd69 100644 --- a/spring-batch-test/pom.xml +++ b/spring-batch-test/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.1 + 5.1.2-SNAPSHOT spring-batch-test Spring Batch Test From 0d06a7c46a7198e9bc01cc05de2fe1cea7726ca6 Mon Sep 17 00:00:00 2001 From: Mario Petrovski Date: Wed, 28 Feb 2024 13:58:38 +0100 Subject: [PATCH 17/55] Update deprecated code that uses StepExecutionListenerSupport Closes #4538 --- .../modules/ROOT/pages/step/controlling-flow.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-batch-docs/modules/ROOT/pages/step/controlling-flow.adoc b/spring-batch-docs/modules/ROOT/pages/step/controlling-flow.adoc index 7d3e70ab23..03670bc31b 100644 --- a/spring-batch-docs/modules/ROOT/pages/step/controlling-flow.adoc +++ b/spring-batch-docs/modules/ROOT/pages/step/controlling-flow.adoc @@ -294,14 +294,14 @@ the condition of the execution having skipped records, as the following example [source, java] ---- -public class SkipCheckingListener extends StepExecutionListenerSupport { +public class SkipCheckingListener implements StepExecutionListener { + @Override public ExitStatus afterStep(StepExecution stepExecution) { String exitCode = stepExecution.getExitStatus().getExitCode(); if (!exitCode.equals(ExitStatus.FAILED.getExitCode()) && - stepExecution.getSkipCount() > 0) { + stepExecution.getSkipCount() > 0) { return new ExitStatus("COMPLETED WITH SKIPS"); - } - else { + } else { return null; } } From 2c0bddc1e11f11d7b108b69b989f77e59f935f8f Mon Sep 17 00:00:00 2001 From: Yejin Choi <63734765+chldppwls12@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:11:26 +0900 Subject: [PATCH 18/55] Fix incorrect code example in documentation Issue #4550 --- spring-batch-docs/modules/ROOT/pages/step/tasklet.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-batch-docs/modules/ROOT/pages/step/tasklet.adoc b/spring-batch-docs/modules/ROOT/pages/step/tasklet.adoc index 2613e34878..7ad23b8dae 100644 --- a/spring-batch-docs/modules/ROOT/pages/step/tasklet.adoc +++ b/spring-batch-docs/modules/ROOT/pages/step/tasklet.adoc @@ -122,7 +122,7 @@ public class FileDeletingTasklet implements Tasklet, InitializingBean { public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { File dir = directory.getFile(); - Assert.state(dir.isDirectory()); + Assert.state(dir.isDirectory(), "The resource must be a directory"); File[] files = dir.listFiles(); for (int i = 0; i < files.length; i++) { @@ -140,7 +140,7 @@ public class FileDeletingTasklet implements Tasklet, InitializingBean { } public void afterPropertiesSet() throws Exception { - Assert.state(directory != null, "directory must be set"); + Assert.state(directory != null, "Directory must be set"); } } ---- From dbb4e21b54b77d9fde9053145a0c71029c2ff78f Mon Sep 17 00:00:00 2001 From: hwan33 Date: Sat, 18 Nov 2023 20:35:59 +0900 Subject: [PATCH 19/55] Fix misleading documentation regarding the ItemWriteListener Resolves #4400 --- .../chunk-oriented-processing/intercepting-execution.adoc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spring-batch-docs/modules/ROOT/pages/step/chunk-oriented-processing/intercepting-execution.adoc b/spring-batch-docs/modules/ROOT/pages/step/chunk-oriented-processing/intercepting-execution.adoc index bdb7f57b61..142cc7772a 100644 --- a/spring-batch-docs/modules/ROOT/pages/step/chunk-oriented-processing/intercepting-execution.adoc +++ b/spring-batch-docs/modules/ROOT/pages/step/chunk-oriented-processing/intercepting-execution.adoc @@ -207,9 +207,10 @@ public interface ItemWriteListener extends StepListener { ---- The `beforeWrite` method is called before `write` on the `ItemWriter` and is handed the -list of items that is written. The `afterWrite` method is called after the item has been -successfully written. If there was an error while writing, the `onWriteError` method is -called. The exception encountered and the item that was attempted to be written are +list of items that is written. The `afterWrite` method is called after the items have been +successfully written, but before committing the transaction associated with the chunk's processing. +If there was an error while writing, the `onWriteError` method is called. +The exception encountered and the item that was attempted to be written are provided, so that they can be logged. The annotations corresponding to this interface are: From 5b4685ea2c4220b2bfcd345de84b457bf7abd5f1 Mon Sep 17 00:00:00 2001 From: Mustafa Yanar Date: Mon, 4 Mar 2024 22:07:58 +0300 Subject: [PATCH 20/55] Fix output chunk end property in ChunkProcessor implementations Resolves #4560 --- .../step/item/FaultTolerantChunkProcessor.java | 6 ++++-- .../batch/core/step/item/SimpleChunkProcessor.java | 5 ++++- .../item/FaultTolerantChunkProcessorTests.java | 13 ++++++++++++- .../core/step/item/SimpleChunkProcessorTests.java | 14 +++++++++++++- .../java/org/springframework/batch/item/Chunk.java | 9 ++++++++- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java index f1eb7321f5..ecb797111c 100755 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -306,7 +306,9 @@ else if (shouldSkip(itemProcessSkipPolicy, e, contribution.getStepSkipCount())) break; } } - + if (inputs.isEnd()) { + outputs.setEnd(); + } return outputs; } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java index 813b6eb403..101945bb22 100755 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -340,6 +340,9 @@ protected Chunk transform(StepContribution contribution, Chunk inputs) thr iterator.remove(); } } + if (inputs.isEnd()) { + outputs.setEnd(); + } return outputs; } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessorTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessorTests.java index 5070b277a4..d30e06917e 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessorTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2023 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.util.ArrayList; @@ -97,6 +98,16 @@ public String process(String item) throws Exception { assertEquals(1, contribution.getFilterCount()); } + @Test + void testTransformChunkEnd() throws Exception { + Chunk inputs = new Chunk<>(Arrays.asList("1", "2")); + inputs.setEnd(); + processor.initializeUserData(inputs); + Chunk outputs = processor.transform(contribution, inputs); + assertEquals(Arrays.asList("1", "2"), outputs.getItems()); + assertTrue(outputs.isEnd()); + } + @Test void testFilterCountOnSkip() throws Exception { processor.setProcessSkipPolicy(new AlwaysSkipItemSkipPolicy()); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/SimpleChunkProcessorTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/SimpleChunkProcessorTests.java index e9a7e0e678..5ebcb49ced 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/SimpleChunkProcessorTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/SimpleChunkProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2023 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.batch.core.step.item; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.Arrays; @@ -76,4 +77,15 @@ void testProcess() throws Exception { assertEquals(2, contribution.getWriteCount()); } + @Test + void testTransform() throws Exception { + Chunk inputs = new Chunk<>(); + inputs.add("foo"); + inputs.add("bar"); + inputs.setEnd(); + Chunk outputs = processor.transform(contribution, inputs); + assertEquals(Arrays.asList("foo", "bar"), outputs.getItems()); + assertTrue(outputs.isEnd()); + } + } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/Chunk.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/Chunk.java index 4cdfa1c7e6..aababa36c2 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/Chunk.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/Chunk.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -154,6 +154,13 @@ public int size() { /** * Flag to indicate if the source data is exhausted. + * + *

+ * Note: This may return false if the last chunk has the same number of items as the + * configured commit interval. Consequently, in such cases,there will be a last empty + * chunk that won't be processed. It is recommended to consider this behavior when + * utilizing this method. + *

* @return true if there is no more data to process */ public boolean isEnd() { From 899343a69b369c9097943355175257566bf5a0bd Mon Sep 17 00:00:00 2001 From: injae-kim Date: Wed, 13 Mar 2024 01:10:12 +0900 Subject: [PATCH 21/55] Fix SystemCommandTasklet to propagate error when exit status is failed Fixes #4483 --- .../core/step/tasklet/SystemCommandTasklet.java | 14 +++++++++++--- .../SystemCommandTaskletIntegrationTests.java | 7 +++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java index b35a228a4d..4499279e8e 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,6 +60,7 @@ * @author Robert Kasanicky * @author Will Schipp * @author Mahmoud Ben Hassine + * @author Injae Kim */ public class SystemCommandTasklet implements StepExecutionListener, StoppableTasklet, InitializingBean { @@ -121,8 +122,15 @@ public RepeatStatus execute(StepContribution contribution, ChunkContext chunkCon } if (systemCommandTask.isDone()) { - contribution.setExitStatus(systemProcessExitCodeMapper.getExitStatus(systemCommandTask.get())); - return RepeatStatus.FINISHED; + Integer exitCode = systemCommandTask.get(); + ExitStatus exitStatus = systemProcessExitCodeMapper.getExitStatus(exitCode); + contribution.setExitStatus(exitStatus); + if (ExitStatus.FAILED.equals(exitStatus)) { + throw new SystemCommandException("Execution of system command failed with exit code " + exitCode); + } + else { + return RepeatStatus.FINISHED; + } } else if (System.currentTimeMillis() - t0 > timeout) { systemCommandTask.cancel(interruptOnCancel); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/tasklet/SystemCommandTaskletIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/tasklet/SystemCommandTaskletIntegrationTests.java index 006d9ed877..b703d91ee3 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/tasklet/SystemCommandTaskletIntegrationTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/tasklet/SystemCommandTaskletIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2023 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -323,9 +323,8 @@ public void testExecuteWithFailedCommandRunnerMockExecution() throws Exception { tasklet.setCommand(command); tasklet.afterPropertiesSet(); - RepeatStatus exitStatus = tasklet.execute(stepContribution, null); - - assertEquals(RepeatStatus.FINISHED, exitStatus); + Exception exception = assertThrows(SystemCommandException.class, () -> tasklet.execute(stepContribution, null)); + assertTrue(exception.getMessage().contains("failed with exit code")); assertEquals(ExitStatus.FAILED, stepContribution.getExitStatus()); } From c451e6be90027b1c916ca52a22ed59a751cb9054 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Mon, 25 Mar 2024 11:26:51 +0100 Subject: [PATCH 22/55] Add native runtime hints for remote partitioning types Resolves #4564 --- .../integration/aot/IntegrationRuntimeHints.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/aot/IntegrationRuntimeHints.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/aot/IntegrationRuntimeHints.java index 72674495fb..5f42caf800 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/aot/IntegrationRuntimeHints.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/aot/IntegrationRuntimeHints.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 the original author or authors. + * Copyright 2023-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,9 @@ import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.batch.integration.chunk.ChunkRequest; import org.springframework.batch.integration.chunk.ChunkResponse; +import org.springframework.batch.integration.partition.MessageChannelPartitionHandler; +import org.springframework.batch.integration.partition.StepExecutionRequest; +import org.springframework.batch.integration.partition.StepExecutionRequestHandler; /** * AOT hints for Spring Batch integration module. @@ -32,12 +35,16 @@ public class IntegrationRuntimeHints implements RuntimeHintsRegistrar { @Override public void registerHints(RuntimeHints hints, ClassLoader classLoader) { // reflection hints - hints.reflection().registerType(ChunkRequest.class, MemberCategory.values()); - hints.reflection().registerType(ChunkResponse.class, MemberCategory.values()); + MemberCategory[] memberCategories = MemberCategory.values(); + hints.reflection().registerType(ChunkRequest.class, memberCategories); + hints.reflection().registerType(ChunkResponse.class, memberCategories); + hints.reflection().registerType(StepExecutionRequestHandler.class, memberCategories); + hints.reflection().registerType(MessageChannelPartitionHandler.class, memberCategories); // serialization hints hints.serialization().registerType(ChunkRequest.class); hints.serialization().registerType(ChunkResponse.class); + hints.serialization().registerType(StepExecutionRequest.class); } } From ee6d68a547a0acf007b829feab0bb01395f9cc68 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Thu, 18 Apr 2024 12:40:28 +0200 Subject: [PATCH 23/55] Upgrade Spring dependencies to latest snapshots --- pom.xml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index c1652dde92..b42cd7738f 100644 --- a/pom.xml +++ b/pom.xml @@ -61,19 +61,19 @@ 17 - 6.1.4 - 2.0.5 - 6.2.2 - 1.12.3 + 6.1.7-SNAPSHOT + 2.0.6-SNAPSHOT + 6.2.5-SNAPSHOT + 1.12.6-SNAPSHOT - 3.2.3 - 3.2.3 - 3.2.3 - 4.2.3 - 3.1.2 - 3.1.2 - 3.2.2 + 3.2.6-SNAPSHOT + 3.2.6-SNAPSHOT + 3.2.6-SNAPSHOT + 4.2.6-SNAPSHOT + 3.1.5-SNAPSHOT + 3.1.5-SNAPSHOT + 3.2.4-SNAPSHOT 2.15.4 1.11.3 @@ -92,7 +92,7 @@ 3.0.2 - 1.2.3 + 1.2.6-SNAPSHOT 1.4.20 4.13.2 From cc56744ddefbf81928debc92475b61f700e11af2 Mon Sep 17 00:00:00 2001 From: Henning Poettker Date: Thu, 28 Dec 2023 02:12:11 +0100 Subject: [PATCH 24/55] Fix SimpleBinaryBufferedReaderFactory for longer endings Resolves #811 --- .../SimpleBinaryBufferedReaderFactory.java | 19 ++++++++------- ...impleBinaryBufferedReaderFactoryTests.java | 23 +++++++++++++++---- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/SimpleBinaryBufferedReaderFactory.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/SimpleBinaryBufferedReaderFactory.java index dba352efff..6b8fede984 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/SimpleBinaryBufferedReaderFactory.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/SimpleBinaryBufferedReaderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,25 +123,24 @@ private boolean isEndOfLine(StringBuilder buffer, StringBuilder candidate, int n } char c = (char) next; - if (ending.charAt(0) == c || candidate.length() > 0) { + if (ending.charAt(0) == c || !candidate.isEmpty()) { candidate.append(c); } - - if (candidate.length() == 0) { + else { buffer.append(c); return false; } - boolean end = ending.equals(candidate.toString()); - if (end) { + if (ending.contentEquals(candidate)) { candidate.delete(0, candidate.length()); + return true; } - else if (candidate.length() >= ending.length()) { - buffer.append(candidate); - candidate.delete(0, candidate.length()); + while (!ending.startsWith(candidate.toString())) { + buffer.append(candidate.charAt(0)); + candidate.delete(0, 1); } - return end; + return false; } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/SimpleBinaryBufferedReaderFactoryTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/SimpleBinaryBufferedReaderFactoryTests.java index 0a814af5aa..202fcc6476 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/SimpleBinaryBufferedReaderFactoryTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/SimpleBinaryBufferedReaderFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ import java.io.BufferedReader; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.core.io.ByteArrayResource; /** @@ -75,16 +77,27 @@ void testCreateWithLineEndingAtEnd() throws Exception { assertNull(reader.readLine()); } - @Test - void testCreateWithFalseLineEnding() throws Exception { + @ParameterizedTest + @ValueSource(strings = { "||", "|||" }) + void testCreateWithFalseLineEnding(String lineEnding) throws Exception { SimpleBinaryBufferedReaderFactory factory = new SimpleBinaryBufferedReaderFactory(); - factory.setLineEnding("||"); + factory.setLineEnding(lineEnding); @SuppressWarnings("resource") - BufferedReader reader = factory.create(new ByteArrayResource("a|b||".getBytes()), "UTF-8"); + BufferedReader reader = factory.create(new ByteArrayResource(("a|b" + lineEnding).getBytes()), "UTF-8"); assertEquals("a|b", reader.readLine()); assertNull(reader.readLine()); } + @Test + void testCreateWithFalseMixedCharacterLineEnding() throws Exception { + SimpleBinaryBufferedReaderFactory factory = new SimpleBinaryBufferedReaderFactory(); + factory.setLineEnding("#@"); + @SuppressWarnings("resource") + BufferedReader reader = factory.create(new ByteArrayResource(("a##@").getBytes()), "UTF-8"); + assertEquals("a#", reader.readLine()); + assertNull(reader.readLine()); + } + @Test void testCreateWithIncompleteLineEnding() throws Exception { SimpleBinaryBufferedReaderFactory factory = new SimpleBinaryBufferedReaderFactory(); From 32e5af00b1c273e4007c6b7fd5ef593453d97b31 Mon Sep 17 00:00:00 2001 From: Seungrae Date: Wed, 24 Apr 2024 18:37:56 +0900 Subject: [PATCH 25/55] Fix code sample that uses deprecated StepBuilderFactory Issue #4582 --- spring-batch-docs/modules/ROOT/pages/scalability.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-batch-docs/modules/ROOT/pages/scalability.adoc b/spring-batch-docs/modules/ROOT/pages/scalability.adoc index 5836fddf56..b00353c4e6 100644 --- a/spring-batch-docs/modules/ROOT/pages/scalability.adoc +++ b/spring-batch-docs/modules/ROOT/pages/scalability.adoc @@ -346,8 +346,8 @@ configuration: [source, java] ---- @Bean -public Step step1Manager() { - return stepBuilderFactory.get("step1.manager") +public Step step1Manager(JobRepository jobRepository) { + return new StepBuilder("step1.manager", jobRepository) .partitioner("step1", partitioner()) .step(step1()) .gridSize(10) From 97cc5cf3219cc73a482a1bab0420b6dd82703581 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Mon, 29 Apr 2024 16:03:03 +0200 Subject: [PATCH 26/55] Improve error messages in JobParametersBuilder Resolves #4581 --- .../batch/core/JobParametersBuilder.java | 16 ++++++++++++---- .../batch/core/JobParametersBuilderTests.java | 10 +++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java index 3450f4894a..9727fa52a5 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java @@ -105,6 +105,7 @@ public JobParametersBuilder addString(String key, @NonNull String parameter) { * @return a reference to this object. */ public JobParametersBuilder addString(String key, @NonNull String parameter, boolean identifying) { + Assert.notNull(parameter, "Value for parameter '" + key + "' must not be null"); this.parameterMap.put(key, new JobParameter<>(parameter, String.class, identifying)); return this; } @@ -128,6 +129,7 @@ public JobParametersBuilder addDate(String key, @NonNull Date parameter) { * @return a reference to this object. */ public JobParametersBuilder addDate(String key, @NonNull Date parameter, boolean identifying) { + Assert.notNull(parameter, "Value for parameter '" + key + "' must not be null"); this.parameterMap.put(key, new JobParameter<>(parameter, Date.class, identifying)); return this; } @@ -151,6 +153,7 @@ public JobParametersBuilder addLocalDate(String key, @NonNull LocalDate paramete * @return a reference to this object. */ public JobParametersBuilder addLocalDate(String key, @NonNull LocalDate parameter, boolean identifying) { + Assert.notNull(parameter, "Value for parameter '" + key + "' must not be null"); this.parameterMap.put(key, new JobParameter<>(parameter, LocalDate.class, identifying)); return this; } @@ -174,6 +177,7 @@ public JobParametersBuilder addLocalTime(String key, @NonNull LocalTime paramete * @return a reference to this object. */ public JobParametersBuilder addLocalTime(String key, @NonNull LocalTime parameter, boolean identifying) { + Assert.notNull(parameter, "Value for parameter '" + key + "' must not be null"); this.parameterMap.put(key, new JobParameter<>(parameter, LocalTime.class, identifying)); return this; } @@ -197,6 +201,7 @@ public JobParametersBuilder addLocalDateTime(String key, @NonNull LocalDateTime * @return a reference to this object. */ public JobParametersBuilder addLocalDateTime(String key, @NonNull LocalDateTime parameter, boolean identifying) { + Assert.notNull(parameter, "Value for parameter '" + key + "' must not be null"); this.parameterMap.put(key, new JobParameter<>(parameter, LocalDateTime.class, identifying)); return this; } @@ -220,6 +225,7 @@ public JobParametersBuilder addLong(String key, @NonNull Long parameter) { * @return a reference to this object. */ public JobParametersBuilder addLong(String key, @NonNull Long parameter, boolean identifying) { + Assert.notNull(parameter, "Value for parameter '" + key + "' must not be null"); this.parameterMap.put(key, new JobParameter<>(parameter, Long.class, identifying)); return this; } @@ -243,6 +249,7 @@ public JobParametersBuilder addDouble(String key, @NonNull Double parameter) { * @return a reference to this object. */ public JobParametersBuilder addDouble(String key, @NonNull Double parameter, boolean identifying) { + Assert.notNull(parameter, "Value for parameter '" + key + "' must not be null"); this.parameterMap.put(key, new JobParameter<>(parameter, Double.class, identifying)); return this; } @@ -285,27 +292,28 @@ public JobParametersBuilder addJobParameter(String key, JobParameter jobParam /** * Add a job parameter. * @param name the name of the parameter - * @param value the value of the parameter + * @param value the value of the parameter. Must not be {@code null}. * @param type the type of the parameter * @param identifying true if the parameter is identifying. false otherwise * @return a reference to this object. * @param the type of the parameter * @since 5.0 */ - public JobParametersBuilder addJobParameter(String name, T value, Class type, boolean identifying) { + public JobParametersBuilder addJobParameter(String name, @NonNull T value, Class type, boolean identifying) { + Assert.notNull(value, "Value for parameter '" + name + "' must not be null"); return addJobParameter(name, new JobParameter<>(value, type, identifying)); } /** * Add an identifying job parameter. * @param name the name of the parameter - * @param value the value of the parameter + * @param value the value of the parameter. Must not be {@code null}. * @param type the type of the parameter * @return a reference to this object. * @param the type of the parameter * @since 5.0 */ - public JobParametersBuilder addJobParameter(String name, T value, Class type) { + public JobParametersBuilder addJobParameter(String name, @NonNull T value, Class type) { return addJobParameter(name, value, type, true); } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersBuilderTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersBuilderTests.java index 2f5cdb5d6e..220dfc4724 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersBuilderTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2023 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Set; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -85,6 +86,13 @@ void testAddingExistingJobParameters() { assertEquals(finalParams.getString("baz"), "quix"); } + @Test + void testAddingNullJobParameters() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> new JobParametersBuilder().addString("foo", null).toJobParameters()); + Assertions.assertEquals("Value for parameter 'foo' must not be null", exception.getMessage()); + } + @Test void testNonIdentifyingParameters() { this.parametersBuilder.addDate("SCHEDULE_DATE", date, false); From 6231e1c26f2d6b003a325d95c35be13feb057758 Mon Sep 17 00:00:00 2001 From: Cameron Kirk Date: Sun, 12 May 2024 09:31:09 -0700 Subject: [PATCH 27/55] Fix typo in java-config.adoc Issue #4591 --- spring-batch-docs/modules/ROOT/pages/job/java-config.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-batch-docs/modules/ROOT/pages/job/java-config.adoc b/spring-batch-docs/modules/ROOT/pages/job/java-config.adoc index 3cbcb727cc..472650b763 100644 --- a/spring-batch-docs/modules/ROOT/pages/job/java-config.adoc +++ b/spring-batch-docs/modules/ROOT/pages/job/java-config.adoc @@ -42,6 +42,7 @@ public class MyJobConfiguration { return new JdbcTransactionManager(dataSource); } + @Bean public Job job(JobRepository jobRepository) { return new JobBuilder("myJob", jobRepository) //define job flow as needed From 494abf1a8ac68940ae6e41e3d8e68cab95321459 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Tue, 14 May 2024 10:42:08 +0200 Subject: [PATCH 28/55] Fix command syntax in documentation deployment scripts --- .github/workflows/continuous-integration-51x.yml | 2 +- .github/workflows/documentation-upload.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous-integration-51x.yml b/.github/workflows/continuous-integration-51x.yml index 1ca740a70d..25ae182b1f 100644 --- a/.github/workflows/continuous-integration-51x.yml +++ b/.github/workflows/continuous-integration-51x.yml @@ -55,5 +55,5 @@ jobs: working-directory: spring-batch-docs/target run: | unzip spring-batch-$PROJECT_VERSION-javadocs.zip - ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST cd $DOCS_PATH && mkdir -p $PROJECT_VERSION/api + ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST "cd $DOCS_PATH && mkdir -p $PROJECT_VERSION/api" scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$PROJECT_VERSION/api diff --git a/.github/workflows/documentation-upload.yml b/.github/workflows/documentation-upload.yml index 5eae40a13a..709597a3ca 100644 --- a/.github/workflows/documentation-upload.yml +++ b/.github/workflows/documentation-upload.yml @@ -57,7 +57,7 @@ jobs: working-directory: spring-batch-docs/target run: | unzip spring-batch-$RELEASE_VERSION-javadocs.zip - ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST cd $DOCS_PATH && mkdir -p $RELEASE_VERSION/api + ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST "cd $DOCS_PATH && mkdir -p $RELEASE_VERSION/api" scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$RELEASE_VERSION/api unzip spring-batch-$RELEASE_VERSION-schemas.zip From b94f7cfe36968b075f1d96feb33ce050d0a18af7 Mon Sep 17 00:00:00 2001 From: ChangYong Date: Wed, 15 May 2024 15:15:54 +0900 Subject: [PATCH 29/55] Fix incorrect link in appendix Issue #4595 --- spring-batch-docs/modules/ROOT/pages/appendix.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-batch-docs/modules/ROOT/pages/appendix.adoc b/spring-batch-docs/modules/ROOT/pages/appendix.adoc index 12de632126..5d2151f077 100644 --- a/spring-batch-docs/modules/ROOT/pages/appendix.adoc +++ b/spring-batch-docs/modules/ROOT/pages/appendix.adoc @@ -42,7 +42,7 @@ This reader stores message offsets in the execution context to support restart c |`ItemReaderAdapter`|Adapts any class to the `ItemReader` interface.|Yes |`JdbcCursorItemReader`|Reads from a database cursor over JDBC. See - link:readersAndWriters.html#cursorBasedItemReaders["`Cursor-based ItemReaders`"].|No + link:readers-and-writers/database.html#cursorBasedItemReaders["`Cursor-based ItemReaders`"].|No |`JdbcPagingItemReader`|Given an SQL statement, pages through the rows, such that large datasets can be read without running out of memory.|Yes From 93fd2c9a3f1dcdab5cbd59936f16ac497be57d72 Mon Sep 17 00:00:00 2001 From: Henning Poettker Date: Sun, 19 May 2024 19:29:31 +0200 Subject: [PATCH 30/55] Keep heap lean during remote partition polling Resolves #4598 --- .../MessageChannelPartitionHandler.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/partition/MessageChannelPartitionHandler.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/partition/MessageChannelPartitionHandler.java index a5cc624196..f0c710c544 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/partition/MessageChannelPartitionHandler.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/partition/MessageChannelPartitionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -251,24 +251,22 @@ protected Set doHandle(StepExecution managerStepExecution, private Set pollReplies(final StepExecution managerStepExecution, final Set split) throws Exception { - final Set result = new HashSet<>(split.size()); + Set partitionStepExecutionIds = split.stream().map(StepExecution::getId).collect(Collectors.toSet()); Callable> callback = () -> { - Set currentStepExecutionIds = split.stream().map(StepExecution::getId).collect(Collectors.toSet()); JobExecution jobExecution = jobExplorer.getJobExecution(managerStepExecution.getJobExecutionId()); - jobExecution.getStepExecutions() + Set finishedStepExecutions = jobExecution.getStepExecutions() .stream() - .filter(stepExecution -> currentStepExecutionIds.contains(stepExecution.getId())) - .filter(stepExecution -> !result.contains(stepExecution)) + .filter(stepExecution -> partitionStepExecutionIds.contains(stepExecution.getId())) .filter(stepExecution -> !stepExecution.getStatus().isRunning()) - .forEach(result::add); + .collect(Collectors.toSet()); if (logger.isDebugEnabled()) { logger.debug(String.format("Currently waiting on %s partitions to finish", split.size())); } - if (result.size() == split.size()) { - return result; + if (finishedStepExecutions.size() == split.size()) { + return finishedStepExecutions; } else { return null; From 6be418d1096e051477985a61b584825e980d3fca Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 22 May 2024 12:03:37 +0200 Subject: [PATCH 31/55] Prepare release 5.1.2 --- pom.xml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index b42cd7738f..b4bde8ce6c 100644 --- a/pom.xml +++ b/pom.xml @@ -61,38 +61,38 @@ 17 - 6.1.7-SNAPSHOT - 2.0.6-SNAPSHOT - 6.2.5-SNAPSHOT - 1.12.6-SNAPSHOT + 6.1.7 + 2.0.6 + 6.2.5 + 1.12.6 - 3.2.6-SNAPSHOT - 3.2.6-SNAPSHOT - 3.2.6-SNAPSHOT - 4.2.6-SNAPSHOT - 3.1.5-SNAPSHOT - 3.1.5-SNAPSHOT - 3.2.4-SNAPSHOT + 3.2.6 + 3.2.6 + 3.2.6 + 4.2.6 + 3.1.5 + 3.1.5 + 3.2.3 2.15.4 1.11.3 2.10.1 6.3.2.Final 2.1.1 - 2.1.2 + 2.1.3 3.1.0 3.0.2 3.1.0 - 4.0.9 - 4.11.1 + 4.0.10 + 4.11.2 5.10.2 3.0.2 - 1.2.6-SNAPSHOT + 1.2.6 1.4.20 4.13.2 @@ -103,14 +103,14 @@ 2.9.1 2.15.1 2.11.0 - 2.0.12 + 2.0.13 2.7.2 2.2.224 3.45.1.0 10.16.1.1 2.18.13 2.31.2 - 4.0.4 + 4.0.5 2.22.1 8.0.1.Final 5.0.1 From a8f8d0bfa7f6116040a0455aa55da8fa343780ef Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 22 May 2024 12:36:02 +0200 Subject: [PATCH 32/55] Release version 5.1.2 --- pom.xml | 2 +- spring-batch-bom/pom.xml | 2 +- spring-batch-core/pom.xml | 2 +- spring-batch-docs/pom.xml | 2 +- spring-batch-infrastructure/pom.xml | 2 +- spring-batch-integration/pom.xml | 2 +- spring-batch-samples/pom.xml | 2 +- spring-batch-test/pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index b4bde8ce6c..4b14e164c9 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ designed to enable the development of robust batch applications vital for the daily operations of enterprise systems. Spring Batch is part of the Spring Portfolio. - 5.1.2-SNAPSHOT + 5.1.2 pom https://projects.spring.io/spring-batch diff --git a/spring-batch-bom/pom.xml b/spring-batch-bom/pom.xml index ddc89539f0..f6ec18e809 100644 --- a/spring-batch-bom/pom.xml +++ b/spring-batch-bom/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2-SNAPSHOT + 5.1.2 spring-batch-bom pom diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index 233ca61cd0..6d07e6bf95 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2-SNAPSHOT + 5.1.2 spring-batch-core jar diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index 852cc9c831..1b044ed519 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2-SNAPSHOT + 5.1.2 spring-batch-docs Spring Batch Docs diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml index 4da5ddb10a..ebd076dc9a 100644 --- a/spring-batch-infrastructure/pom.xml +++ b/spring-batch-infrastructure/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2-SNAPSHOT + 5.1.2 spring-batch-infrastructure jar diff --git a/spring-batch-integration/pom.xml b/spring-batch-integration/pom.xml index a193782dfb..266c1a75b9 100644 --- a/spring-batch-integration/pom.xml +++ b/spring-batch-integration/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2-SNAPSHOT + 5.1.2 spring-batch-integration Spring Batch Integration diff --git a/spring-batch-samples/pom.xml b/spring-batch-samples/pom.xml index 27aea6dee7..0840e3011a 100644 --- a/spring-batch-samples/pom.xml +++ b/spring-batch-samples/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2-SNAPSHOT + 5.1.2 spring-batch-samples jar diff --git a/spring-batch-test/pom.xml b/spring-batch-test/pom.xml index 982ccadd69..e8d499304e 100644 --- a/spring-batch-test/pom.xml +++ b/spring-batch-test/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2-SNAPSHOT + 5.1.2 spring-batch-test Spring Batch Test From 1fc2e7ce64ff80f34d9bc54145510efbbeca144e Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 22 May 2024 12:36:24 +0200 Subject: [PATCH 33/55] Next development version --- pom.xml | 2 +- spring-batch-bom/pom.xml | 2 +- spring-batch-core/pom.xml | 2 +- spring-batch-docs/pom.xml | 2 +- spring-batch-infrastructure/pom.xml | 2 +- spring-batch-integration/pom.xml | 2 +- spring-batch-samples/pom.xml | 2 +- spring-batch-test/pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 4b14e164c9..e6dfb5f51c 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ designed to enable the development of robust batch applications vital for the daily operations of enterprise systems. Spring Batch is part of the Spring Portfolio. - 5.1.2 + 5.1.3-SNAPSHOT pom https://projects.spring.io/spring-batch diff --git a/spring-batch-bom/pom.xml b/spring-batch-bom/pom.xml index f6ec18e809..6043d9aad5 100644 --- a/spring-batch-bom/pom.xml +++ b/spring-batch-bom/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2 + 5.1.3-SNAPSHOT spring-batch-bom pom diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index 6d07e6bf95..2e91a9a6de 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2 + 5.1.3-SNAPSHOT spring-batch-core jar diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index 1b044ed519..8d6a127a7f 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2 + 5.1.3-SNAPSHOT spring-batch-docs Spring Batch Docs diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml index ebd076dc9a..9e00a2e41a 100644 --- a/spring-batch-infrastructure/pom.xml +++ b/spring-batch-infrastructure/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2 + 5.1.3-SNAPSHOT spring-batch-infrastructure jar diff --git a/spring-batch-integration/pom.xml b/spring-batch-integration/pom.xml index 266c1a75b9..78f03aae3f 100644 --- a/spring-batch-integration/pom.xml +++ b/spring-batch-integration/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2 + 5.1.3-SNAPSHOT spring-batch-integration Spring Batch Integration diff --git a/spring-batch-samples/pom.xml b/spring-batch-samples/pom.xml index 0840e3011a..cb71fb62d0 100644 --- a/spring-batch-samples/pom.xml +++ b/spring-batch-samples/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2 + 5.1.3-SNAPSHOT spring-batch-samples jar diff --git a/spring-batch-test/pom.xml b/spring-batch-test/pom.xml index e8d499304e..7cba0d1104 100644 --- a/spring-batch-test/pom.xml +++ b/spring-batch-test/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.2 + 5.1.3-SNAPSHOT spring-batch-test Spring Batch Test From 101496d2a38304734176d582efa6bd823dfffbcd Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Fri, 24 May 2024 10:02:24 +0200 Subject: [PATCH 34/55] Fix http link syntax in repeat.adoc (cherry picked from commit cb8d045eac9faba258acce63cb90b66461d6253d) --- spring-batch-docs/modules/ROOT/pages/repeat.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-batch-docs/modules/ROOT/pages/repeat.adoc b/spring-batch-docs/modules/ROOT/pages/repeat.adoc index 4836d338b2..7836d11043 100644 --- a/spring-batch-docs/modules/ROOT/pages/repeat.adoc +++ b/spring-batch-docs/modules/ROOT/pages/repeat.adoc @@ -207,7 +207,7 @@ Java:: The following example uses Java configuration to repeat a service call to a method called `processMessage` (for more detail on how to configure AOP interceptors, see the -<>): +https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop[Spring User Guide]): + [source, java] ---- @@ -234,7 +234,7 @@ XML:: The following example shows declarative iteration that uses the Spring AOP namespace to repeat a service call to a method called `processMessage` (for more detail on how to configure AOP interceptors, see the -<>): +https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop[Spring User Guide]): + [source, xml] ---- From 6dc28da3a700aae723bd94dde7771701fb843d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20B=C3=BCld?= Date: Tue, 21 May 2024 15:40:23 +0200 Subject: [PATCH 35/55] Fix grammatical error in restart.adoc Issue #4600 --- .../ROOT/pages/step/chunk-oriented-processing/restart.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-batch-docs/modules/ROOT/pages/step/chunk-oriented-processing/restart.adoc b/spring-batch-docs/modules/ROOT/pages/step/chunk-oriented-processing/restart.adoc index 8f4af6f71e..20e80bd72d 100644 --- a/spring-batch-docs/modules/ROOT/pages/step/chunk-oriented-processing/restart.adoc +++ b/spring-batch-docs/modules/ROOT/pages/step/chunk-oriented-processing/restart.adoc @@ -9,7 +9,7 @@ require some specific configuration. == Setting a Start Limit There are many scenarios where you may want to control the number of times a `Step` can -be started. For example, you might need to configure a particular `Step` might so that it +be started. For example, you might need to configure a particular `Step` so that it runs only once because it invalidates some resource that must be fixed manually before it can be run again. This is configurable on the step level, since different steps may have different requirements. A `Step` that can be executed only once can exist as part of the From 8730c33e49947d455c9a898f5eb318c10b581f53 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Fri, 24 May 2024 15:58:41 +0200 Subject: [PATCH 36/55] Update antora resources --- spring-batch-docs/antora-playbook.yml | 5 +++-- spring-batch-docs/pom.xml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spring-batch-docs/antora-playbook.yml b/spring-batch-docs/antora-playbook.yml index 037f9e80d6..bbf8fac2a9 100644 --- a/spring-batch-docs/antora-playbook.yml +++ b/spring-batch-docs/antora-playbook.yml @@ -4,9 +4,10 @@ antora: extensions: - '@springio/antora-extensions/partial-build-extension' + - '@antora/atlas-extension' + - require: '@springio/antora-extensions/latest-version-extension' - require: '@springio/antora-extensions/inject-collector-cache-config-extension' - '@antora/collector-extension' - - '@antora/atlas-extension' - require: '@springio/antora-extensions/root-component-extension' root_component_name: 'batch' - '@springio/antora-extensions/static-page-extension' @@ -37,5 +38,5 @@ runtime: format: pretty ui: bundle: - url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.7/ui-bundle.zip + url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.15/ui-bundle.zip snapshot: true \ No newline at end of file diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index 8d6a127a7f..60670cf4cf 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -26,7 +26,7 @@ @antora/atlas-extension@1.0.0-alpha.1 @antora/collector-extension@1.0.0-alpha.3 @asciidoctor/tabs@1.0.0-beta.3 - @springio/antora-extensions@1.8.2 + @springio/antora-extensions@1.11.1 @springio/asciidoctor-extensions@1.0.0-alpha.9 From 0b2c741e79bf76f6155dea3b216b7cdd109aeb5d Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 29 May 2024 10:09:12 +0200 Subject: [PATCH 37/55] Fix javadocs deployment path --- .github/workflows/continuous-integration-51x.yml | 4 ++-- .github/workflows/documentation-upload.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous-integration-51x.yml b/.github/workflows/continuous-integration-51x.yml index 25ae182b1f..e1e2af9297 100644 --- a/.github/workflows/continuous-integration-51x.yml +++ b/.github/workflows/continuous-integration-51x.yml @@ -55,5 +55,5 @@ jobs: working-directory: spring-batch-docs/target run: | unzip spring-batch-$PROJECT_VERSION-javadocs.zip - ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST "cd $DOCS_PATH && mkdir -p $PROJECT_VERSION/api" - scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$PROJECT_VERSION/api + ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST "cd $DOCS_PATH && mkdir -p $PROJECT_VERSION" + scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$PROJECT_VERSION diff --git a/.github/workflows/documentation-upload.yml b/.github/workflows/documentation-upload.yml index 709597a3ca..3504b512c9 100644 --- a/.github/workflows/documentation-upload.yml +++ b/.github/workflows/documentation-upload.yml @@ -57,8 +57,8 @@ jobs: working-directory: spring-batch-docs/target run: | unzip spring-batch-$RELEASE_VERSION-javadocs.zip - ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST "cd $DOCS_PATH && mkdir -p $RELEASE_VERSION/api" - scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$RELEASE_VERSION/api + ssh -i $HOME/.ssh/key $DOCS_USERNAME@$DOCS_HOST "cd $DOCS_PATH && mkdir -p $RELEASE_VERSION" + scp -i $HOME/.ssh/key -r api $DOCS_USERNAME@$DOCS_HOST:$DOCS_PATH/$RELEASE_VERSION unzip spring-batch-$RELEASE_VERSION-schemas.zip scp -i $HOME/.ssh/key batch/*.xsd $DOCS_USERNAME@$DOCS_HOST:$BATCH_SCHEMA_PATH From d7d16fcc29a26c548223f82d9546cb62eb6418c2 Mon Sep 17 00:00:00 2001 From: Benjamin BONNET Date: Thu, 30 May 2024 11:13:15 +0200 Subject: [PATCH 38/55] Fix typo in spring-batch-architecture.adoc --- .../modules/ROOT/pages/spring-batch-architecture.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-batch-docs/modules/ROOT/pages/spring-batch-architecture.adoc b/spring-batch-docs/modules/ROOT/pages/spring-batch-architecture.adoc index 75e5ab926f..ea0d35f7c9 100644 --- a/spring-batch-docs/modules/ROOT/pages/spring-batch-architecture.adoc +++ b/spring-batch-docs/modules/ROOT/pages/spring-batch-architecture.adoc @@ -252,7 +252,7 @@ advisable). The following image illustrates the partitioning approach: image::partitioned.png[Figure 1.2: Partitioned Process, scaledwidth="60%"] The architecture should be flexible enough to allow dynamic configuration of the number -of partitions. You shoul consider both automatic and user controlled configuration. +of partitions. You should consider both automatic and user controlled configuration. Automatic configuration may be based on such parameters as the input file size and the number of input records. From b7339c2e9641c2ac4428fa059d6faa6b03243e6f Mon Sep 17 00:00:00 2001 From: Jimmy Praet Date: Fri, 6 Sep 2024 23:25:08 +0200 Subject: [PATCH 39/55] Move ORDER BY in getLastStepExecution from DB to java This addresses performance issues with large STEP_EXECUTION table on DB2. Fixes #4657 --- .../batch/core/repository/dao/JdbcStepExecutionDao.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java index 5c53a6f4a0..c086ec3b01 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.concurrent.locks.Lock; @@ -97,7 +98,6 @@ public class JdbcStepExecutionDao extends AbstractJdbcBatchMetadataDao implement FROM %PREFIX%JOB_EXECUTION JE JOIN %PREFIX%STEP_EXECUTION SE ON SE.JOB_EXECUTION_ID = JE.JOB_EXECUTION_ID WHERE JE.JOB_INSTANCE_ID = ? AND SE.STEP_NAME = ? - ORDER BY SE.CREATE_TIME DESC, SE.STEP_EXECUTION_ID DESC """; private static final String CURRENT_VERSION_STEP_EXECUTION = """ @@ -117,6 +117,10 @@ SELECT COUNT(*) WHERE STEP_EXECUTION_ID = ? """; + private static final Comparator BY_CREATE_TIME_DESC_ID_DESC = Comparator + .comparing(StepExecution::getCreateTime, Comparator.reverseOrder()) + .thenComparing(StepExecution::getId, Comparator.reverseOrder()); + private int exitMessageLength = DEFAULT_EXIT_MESSAGE_LENGTH; private DataFieldMaxValueIncrementer stepExecutionIncrementer; @@ -348,6 +352,7 @@ public StepExecution getLastStepExecution(JobInstance jobInstance, String stepNa jobExecution.setVersion(rs.getInt(27)); return new StepExecutionRowMapper(jobExecution).mapRow(rs, rowNum); }, jobInstance.getInstanceId(), stepName); + executions.sort(BY_CREATE_TIME_DESC_ID_DESC); if (executions.isEmpty()) { return null; } From 8f7f37b03b816d32eac264850ed324f51447441a Mon Sep 17 00:00:00 2001 From: jojoldu Date: Sat, 24 Aug 2024 23:55:58 +0900 Subject: [PATCH 40/55] change assertTrue (instanceof) -> assertInstanceOf --- .../step/item/FaultTolerantStepFactoryBeanRetryTests.java | 6 ++++-- .../step/item/RepeatOperationsStepFactoryBeanTests.java | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java index 84cb8a0449..1c755304fe 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,10 +61,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; /** * @author Dave Syer * @author Mahmoud Ben Hassine + * @author jojoldu * */ class FaultTolerantStepFactoryBeanRetryTests { @@ -134,7 +136,7 @@ void testType() { @SuppressWarnings("cast") @Test void testDefaultValue() throws Exception { - assertTrue(factory.getObject() instanceof Step); + assertInstanceOf(Step.class, factory.getObject()); } @Test diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/RepeatOperationsStepFactoryBeanTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/RepeatOperationsStepFactoryBeanTests.java index 88c2982aa3..7f5965dd4e 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/RepeatOperationsStepFactoryBeanTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/RepeatOperationsStepFactoryBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author 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,10 +35,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + /** * @author Dave Syer * @author Mahmoud Ben Hassine + * @author jojoldu * */ class RepeatOperationsStepFactoryBeanTests { @@ -66,7 +69,7 @@ void testType() { @Test @SuppressWarnings("cast") void testDefaultValue() throws Exception { - assertTrue(factory.getObject() instanceof Step); + assertInstanceOf(Step.class, factory.getObject()); } @Test From 127ff8cf845dd0dc7ac7d8a840c0548fbf6336a6 Mon Sep 17 00:00:00 2001 From: Sheel Prabhakar Date: Sat, 29 Jun 2024 07:50:41 +0530 Subject: [PATCH 41/55] Add DatabaseType POSTGRES for the product name EnterpriseDB Resolves #4627 --- .../org/springframework/batch/support/DatabaseType.java | 5 ++++- .../springframework/batch/support/DatabaseTypeTests.java | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/DatabaseType.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/DatabaseType.java index c4086b4539..d727cdc3cc 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/DatabaseType.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/DatabaseType.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -103,6 +103,9 @@ else if (databaseProductName.contains("AS") && (databaseProductVersion.startsWit databaseProductName = JdbcUtils.commonDatabaseName(databaseProductName); } } + else if (StringUtils.hasText(databaseProductName) && databaseProductName.startsWith("EnterpriseDB")) { + databaseProductName = "PostgreSQL"; + } else { databaseProductName = JdbcUtils.commonDatabaseName(databaseProductName); } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeTests.java index 9c786e8310..2374153b3b 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2022 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -138,6 +138,12 @@ void testFromMetaDataForPostgres() throws Exception { assertEquals(POSTGRES, DatabaseType.fromMetaData(ds)); } + @Test + void testFromMetaDataForEnterpriseDB() throws Exception { + DataSource ds = DatabaseTypeTestUtils.getMockDataSource("EnterpriseDB"); + assertEquals(POSTGRES, DatabaseType.fromMetaData(ds)); + } + @Test void testFromMetaDataForSybase() throws Exception { DataSource ds = DatabaseTypeTestUtils.getMockDataSource("Adaptive Server Enterprise"); From 896b8d614e83e178277dab744cace79403df367d Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Thu, 19 Sep 2024 12:01:43 +0200 Subject: [PATCH 42/55] Fix code formatting --- .../core/step/item/FaultTolerantStepFactoryBeanRetryTests.java | 2 +- .../core/step/item/RepeatOperationsStepFactoryBeanTests.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java index 1c755304fe..9f5ec22ea7 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java @@ -136,7 +136,7 @@ void testType() { @SuppressWarnings("cast") @Test void testDefaultValue() throws Exception { - assertInstanceOf(Step.class, factory.getObject()); + assertInstanceOf(Step.class, factory.getObject()); } @Test diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/RepeatOperationsStepFactoryBeanTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/RepeatOperationsStepFactoryBeanTests.java index 7f5965dd4e..f476e4e72c 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/RepeatOperationsStepFactoryBeanTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/RepeatOperationsStepFactoryBeanTests.java @@ -37,7 +37,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertInstanceOf; - /** * @author Dave Syer * @author Mahmoud Ben Hassine @@ -69,7 +68,7 @@ void testType() { @Test @SuppressWarnings("cast") void testDefaultValue() throws Exception { - assertInstanceOf(Step.class, factory.getObject()); + assertInstanceOf(Step.class, factory.getObject()); } @Test From 2239dc734af5f28edfb6b3646fd4f15b188752e5 Mon Sep 17 00:00:00 2001 From: hyejinggu <118355536+hyejinggu@users.noreply.github.com> Date: Sat, 5 Oct 2024 18:52:24 +0900 Subject: [PATCH 43/55] Fix column types in JdbcStepExecutionDao Resolves #4648 --- .../repository/dao/JdbcStepExecutionDao.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java index c086ec3b01..037ad7706c 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java @@ -281,10 +281,9 @@ public void updateStepExecution(StepExecution stepExecution) { stepExecution.getWriteSkipCount(), stepExecution.getRollbackCount(), lastUpdated, stepExecution.getId(), stepExecution.getVersion() }; int count = getJdbcTemplate().update(getQuery(UPDATE_STEP_EXECUTION), parameters, - new int[] { Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR, Types.INTEGER, Types.INTEGER, - Types.INTEGER, Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.INTEGER, - Types.INTEGER, Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.BIGINT, - Types.INTEGER }); + new int[] { Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR, Types.BIGINT, Types.BIGINT, + Types.BIGINT, Types.BIGINT, Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.BIGINT, + Types.BIGINT, Types.BIGINT, Types.BIGINT, Types.TIMESTAMP, Types.BIGINT, Types.INTEGER }); // Avoid concurrent modifications... if (count == 0) { @@ -395,15 +394,15 @@ public StepExecution mapRow(ResultSet rs, int rowNum) throws SQLException { stepExecution.setStartTime(rs.getTimestamp(3) == null ? null : rs.getTimestamp(3).toLocalDateTime()); stepExecution.setEndTime(rs.getTimestamp(4) == null ? null : rs.getTimestamp(4).toLocalDateTime()); stepExecution.setStatus(BatchStatus.valueOf(rs.getString(5))); - stepExecution.setCommitCount(rs.getInt(6)); - stepExecution.setReadCount(rs.getInt(7)); - stepExecution.setFilterCount(rs.getInt(8)); - stepExecution.setWriteCount(rs.getInt(9)); + stepExecution.setCommitCount(rs.getLong(6)); + stepExecution.setReadCount(rs.getLong(7)); + stepExecution.setFilterCount(rs.getLong(8)); + stepExecution.setWriteCount(rs.getLong(9)); stepExecution.setExitStatus(new ExitStatus(rs.getString(10), rs.getString(11))); - stepExecution.setReadSkipCount(rs.getInt(12)); - stepExecution.setWriteSkipCount(rs.getInt(13)); - stepExecution.setProcessSkipCount(rs.getInt(14)); - stepExecution.setRollbackCount(rs.getInt(15)); + stepExecution.setReadSkipCount(rs.getLong(12)); + stepExecution.setWriteSkipCount(rs.getLong(13)); + stepExecution.setProcessSkipCount(rs.getLong(14)); + stepExecution.setRollbackCount(rs.getLong(15)); stepExecution.setLastUpdated(rs.getTimestamp(16) == null ? null : rs.getTimestamp(16).toLocalDateTime()); stepExecution.setVersion(rs.getInt(17)); stepExecution.setCreateTime(rs.getTimestamp(18) == null ? null : rs.getTimestamp(18).toLocalDateTime()); From fb03aab5a3b2d4ec7910586c0b6bf9fdc17e3092 Mon Sep 17 00:00:00 2001 From: pxzxj Date: Wed, 4 Sep 2024 15:39:37 +0800 Subject: [PATCH 44/55] Fix typo in word AsynchItemWriter Resolves #4649 --- .../ROOT/pages/spring-batch-integration/sub-elements.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-batch-docs/modules/ROOT/pages/spring-batch-integration/sub-elements.adoc b/spring-batch-docs/modules/ROOT/pages/spring-batch-integration/sub-elements.adoc index eac14f4e7c..205a8669e2 100644 --- a/spring-batch-docs/modules/ROOT/pages/spring-batch-integration/sub-elements.adoc +++ b/spring-batch-docs/modules/ROOT/pages/spring-batch-integration/sub-elements.adoc @@ -182,7 +182,7 @@ The following example shows the how to add a step-level listener in XML: Asynchronous Processors help you scale the processing of items. In the asynchronous processor use case, an `AsyncItemProcessor` serves as a dispatcher, executing the logic of the `ItemProcessor` for an item on a new thread. Once the item completes, the `Future` is -passed to the `AsynchItemWriter` to be written. +passed to the `AsyncItemWriter` to be written. Therefore, you can increase performance by using asynchronous item processing, basically letting you implement fork-join scenarios. The `AsyncItemWriter` gathers the results and From e4a7bd84dffb10f13853bf402fa0739e2ec9777e Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 23 Oct 2024 05:57:09 +0200 Subject: [PATCH 45/55] Clarify the behaviour of MultiResourceItemWriter with regard to file creation Resolves #4645 --- .../batch/item/file/MultiResourceItemWriter.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemWriter.java index 1480cba407..835abb3527 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemWriter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author 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,11 @@ *

* Note that new resources are created only at chunk boundaries i.e. the number of items * written into one resource is between the limit set by - * {@link #setItemCountLimitPerResource(int)} and (limit + chunk size). + *

+ * This writer will create an output file only when there are items to write, which means + * there would be no empty file created if no items are passed (for example when all items + * are filtered or skipped during the processing phase). + *

* * @param item type * @author Robert Kasanicky From 09df30f4e61d373cee1255cf44f2c63d40c4eaa0 Mon Sep 17 00:00:00 2001 From: Taeik Lim Date: Sun, 9 Jun 2024 22:22:35 +0900 Subject: [PATCH 46/55] Add '@FunctionalInterface' to JobKeyGenerator Resolves #4613 Signed-off-by: Taeik Lim --- .../java/org/springframework/batch/core/JobKeyGenerator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobKeyGenerator.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobKeyGenerator.java index 589434b97f..147a26a37c 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobKeyGenerator.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 the original author or authors. + * Copyright 2013-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,11 @@ * * @author Michael Minella * @author Mahmoud Ben Hassine + * @author Taeik Lim * @param The type of the source data used to calculate the key. * @since 2.2 */ +@FunctionalInterface public interface JobKeyGenerator { /** From bd00cde09f2d75cb2eec7eb026346751aca55aae Mon Sep 17 00:00:00 2001 From: Henning Poettker Date: Sun, 24 Nov 2024 03:24:30 +0100 Subject: [PATCH 47/55] Fix parsing of the `stop` element in step XML Previously, users were forced to set the attribute `exit-code` of the element to `""` as a work-around to prevent failing restarts. Resolves #1287 --- .../configuration/xml/AbstractFlowParser.java | 5 +- .../StopAndRestartFailedJobParserTests.java | 4 +- .../xml/StopAndRestartJobParserTests.java | 4 +- ...startWithCustomExitCodeJobParserTests.java | 69 +++++++++++++++++++ .../xml/StopCustomStatusJobParserTests.java | 4 +- .../xml/StopIncompleteJobParserTests.java | 4 +- .../configuration/xml/StopJobParserTests.java | 4 +- ...AndRestartFailedJobParserTests-context.xml | 2 +- .../StopAndRestartJobParserTests-context.xml | 2 +- ...thCustomExitCodeJobParserTests-context.xml | 16 +++++ ...StopCustomStatusJobParserTests-context.xml | 2 +- .../StopIncompleteJobParserTests-context.xml | 2 +- .../xml/StopJobParserTests-context.xml | 2 +- 13 files changed, 97 insertions(+), 23 deletions(-) create mode 100644 spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartWithCustomExitCodeJobParserTests.java create mode 100644 spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartWithCustomExitCodeJobParserTests-context.xml diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractFlowParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractFlowParser.java index 7ea6394697..02eea1c0f1 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractFlowParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractFlowParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -414,8 +414,7 @@ protected static Collection createTransition(FlowExecutionStatus endBuilder.addConstructorArgValue(abandon); - String nextOnEnd = exitCodeExists ? null : next; - endState = getStateTransitionReference(parserContext, endBuilder.getBeanDefinition(), null, nextOnEnd); + endState = getStateTransitionReference(parserContext, endBuilder.getBeanDefinition(), null, next); next = endName; } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartFailedJobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartFailedJobParserTests.java index b8fe6dedfb..525e2ba2a1 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartFailedJobParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartFailedJobParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the original author or authors. + * Copyright 2006-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,8 +33,6 @@ * */ @SpringJUnitConfig -// FIXME this test fails when upgrading the batch xsd from 2.2 to 3.0: -// https://github.com/spring-projects/spring-batch/issues/1287 class StopAndRestartFailedJobParserTests extends AbstractJobParserTests { @Test diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartJobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartJobParserTests.java index 1702b6f1a3..6f30120f30 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartJobParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartJobParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the original author or authors. + * Copyright 2006-2024 the original author 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,6 @@ * */ @SpringJUnitConfig -// FIXME this test fails when upgrading the batch xsd from 2.2 to 3.0: -// https://github.com/spring-projects/spring-batch/issues/1287 class StopAndRestartJobParserTests extends AbstractJobParserTests { @Test diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartWithCustomExitCodeJobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartWithCustomExitCodeJobParserTests.java new file mode 100644 index 0000000000..375e21bb27 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopAndRestartWithCustomExitCodeJobParserTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2024 the original author 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.batch.core.configuration.xml; + +import org.junit.jupiter.api.Test; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.StepExecution; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Henning Pöttker + */ +@SpringJUnitConfig +class StopAndRestartWithCustomExitCodeJobParserTests extends AbstractJobParserTests { + + @Test + void testStopIncomplete() throws Exception { + + // + // First Launch + // + JobExecution jobExecution = createJobExecution(); + job.execute(jobExecution); + assertEquals(1, stepNamesList.size()); + assertEquals("[s1]", stepNamesList.toString()); + + assertEquals(BatchStatus.STOPPED, jobExecution.getStatus()); + assertEquals("CUSTOM", jobExecution.getExitStatus().getExitCode()); + + StepExecution stepExecution1 = getStepExecution(jobExecution, "s1"); + assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus()); + assertEquals(ExitStatus.COMPLETED.getExitCode(), stepExecution1.getExitStatus().getExitCode()); + + // + // Second Launch + // + stepNamesList.clear(); + jobExecution = createJobExecution(); + job.execute(jobExecution); + assertEquals(1, stepNamesList.size()); // step1 is not executed + assertEquals("[s2]", stepNamesList.toString()); + + assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus()); + assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus()); + + StepExecution stepExecution2 = getStepExecution(jobExecution, "s2"); + assertEquals(BatchStatus.COMPLETED, stepExecution2.getStatus()); + assertEquals(ExitStatus.COMPLETED, stepExecution2.getExitStatus()); + + } + +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests.java index f0fe245e14..e824cd75d9 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the original author or authors. + * Copyright 2006-2024 the original author 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,6 @@ * */ @SpringJUnitConfig -// FIXME this test fails when upgrading the batch xsd from 2.2 to 3.0: -// https://github.com/spring-projects/spring-batch/issues/1287 class StopCustomStatusJobParserTests extends AbstractJobParserTests { @Test diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopIncompleteJobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopIncompleteJobParserTests.java index e6ddfee766..b5e4b8183a 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopIncompleteJobParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopIncompleteJobParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the original author or authors. + * Copyright 2006-2024 the original author 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,6 @@ * */ @SpringJUnitConfig -// FIXME this test fails when upgrading the batch xsd from 2.2 to 3.0: -// https://github.com/spring-projects/spring-batch/issues/1287 class StopIncompleteJobParserTests extends AbstractJobParserTests { @Test diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopJobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopJobParserTests.java index b2f0d75c71..f05c0b6cba 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopJobParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StopJobParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the original author or authors. + * Copyright 2006-2024 the original author 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,8 +34,6 @@ * */ @SpringJUnitConfig -// FIXME this test fails when upgrading the batch xsd from 2.2 to 3.0: -// https://github.com/spring-projects/spring-batch/issues/1287 class StopJobParserTests extends AbstractJobParserTests { @Test diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartFailedJobParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartFailedJobParserTests-context.xml index 189d63ce13..97df1bef5e 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartFailedJobParserTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartFailedJobParserTests-context.xml @@ -2,7 +2,7 @@ diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartJobParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartJobParserTests-context.xml index fe7ed075ed..de0face964 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartJobParserTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartJobParserTests-context.xml @@ -1,7 +1,7 @@ diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartWithCustomExitCodeJobParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartWithCustomExitCodeJobParserTests-context.xml new file mode 100644 index 0000000000..dba05231c4 --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopAndRestartWithCustomExitCodeJobParserTests-context.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests-context.xml index fbb7f4c6a0..93b0a1b4ea 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests-context.xml @@ -1,7 +1,7 @@ diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopIncompleteJobParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopIncompleteJobParserTests-context.xml index ca269dec17..080f44a374 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopIncompleteJobParserTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopIncompleteJobParserTests-context.xml @@ -1,7 +1,7 @@ diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopJobParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopJobParserTests-context.xml index 0f67bf801d..5be5d43f6b 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopJobParserTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopJobParserTests-context.xml @@ -1,7 +1,7 @@ From aafecb93d4d9713ddc8c5dc9622ed7ba14ba2547 Mon Sep 17 00:00:00 2001 From: doontagi Date: Sun, 24 Mar 2024 22:55:09 +0900 Subject: [PATCH 48/55] Fix unfinished step in parallel flow Resolves #3939 Signed-off-by: Mahmoud Ben Hassine --- .../job/flow/support/state/SplitState.java | 13 ++++-- .../core/job/builder/FlowJobBuilderTests.java | 41 ++++++++++++++++++- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/SplitState.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/SplitState.java index 0de11a3489..c9ab0c0152 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/SplitState.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/SplitState.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 the original author or authors. + * Copyright 2006-2024 the original author 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 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; @@ -119,7 +120,7 @@ public FlowExecutionStatus handle(final FlowExecutor executor) throws Exception FlowExecutionStatus parentSplitStatus = parentSplit == null ? null : parentSplit.handle(executor); Collection results = new ArrayList<>(); - + List exceptions = new ArrayList<>(); // Could use a CompletionService here? for (Future task : tasks) { try { @@ -129,14 +130,18 @@ public FlowExecutionStatus handle(final FlowExecutor executor) throws Exception // Unwrap the expected exceptions Throwable cause = e.getCause(); if (cause instanceof Exception) { - throw (Exception) cause; + exceptions.add((Exception) cause); } else { - throw e; + exceptions.add(e); } } } + if (!exceptions.isEmpty()) { + throw exceptions.get(0); + } + FlowExecutionStatus flowExecutionStatus = doAggregation(results, executor); if (parentSplitStatus != null) { return Collections.max(Arrays.asList(flowExecutionStatus, parentSplitStatus)); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/builder/FlowJobBuilderTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/builder/FlowJobBuilderTests.java index 14e61a58a0..c3dea9e369 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/builder/FlowJobBuilderTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/builder/FlowJobBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,14 @@ package org.springframework.batch.core.job.builder; import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.sql.DataSource; import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.batch.core.BatchStatus; @@ -45,6 +48,8 @@ import org.springframework.batch.core.step.StepSupport; import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.item.support.ListItemReader; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -369,4 +374,38 @@ public JdbcTransactionManager transactionManager(DataSource dataSource) { } + @Test + public void testBuildSplitWithParallelFlow() throws InterruptedException { + CountDownLatch countDownLatch = new CountDownLatch(1); + Step longExecutingStep = new StepBuilder("longExecutingStep", jobRepository).tasklet((stepContribution, b) -> { + Thread.sleep(500L); + return RepeatStatus.FINISHED; + }, new ResourcelessTransactionManager()).build(); + + Step interruptedStep = new StepBuilder("interruptedStep", jobRepository).tasklet((stepContribution, b) -> { + stepContribution.getStepExecution().setTerminateOnly(); + return RepeatStatus.FINISHED; + }, new ResourcelessTransactionManager()).build(); + + Step nonExecutableStep = new StepBuilder("nonExecutableStep", jobRepository).tasklet((stepContribution, b) -> { + countDownLatch.countDown(); + return RepeatStatus.FINISHED; + }, new ResourcelessTransactionManager()).build(); + + Flow twoStepFlow = new FlowBuilder("twoStepFlow").start(longExecutingStep) + .next(nonExecutableStep) + .build(); + Flow interruptedFlow = new FlowBuilder("interruptedFlow").start(interruptedStep).build(); + + Flow splitFlow = new FlowBuilder("splitFlow").split(new SimpleAsyncTaskExecutor()) + .add(interruptedFlow, twoStepFlow) + .build(); + FlowJobBuilder jobBuilder = new JobBuilder("job", jobRepository).start(splitFlow).build(); + jobBuilder.preventRestart().build().execute(execution); + + boolean isExecutedNonExecutableStep = countDownLatch.await(1, TimeUnit.SECONDS); + assertEquals(BatchStatus.STOPPED, execution.getStatus()); + Assertions.assertFalse(isExecutedNonExecutableStep); + } + } From e0440300b1f9b3d96d7fd52e0b0c87c1f5c3d7d1 Mon Sep 17 00:00:00 2001 From: Henning Poettker Date: Fri, 6 Dec 2024 17:41:00 +0100 Subject: [PATCH 49/55] Add state reset on close of `AbstractPaginatedDataItemReader` Resolves #1086 --- .../data/AbstractPaginatedDataItemReader.java | 10 +++++++++- .../item/data/MongoPagingItemReaderTests.java | 18 +++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/AbstractPaginatedDataItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/AbstractPaginatedDataItemReader.java index c7982e506d..043e54b7ba 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/AbstractPaginatedDataItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/AbstractPaginatedDataItemReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -103,6 +103,14 @@ protected void doOpen() throws Exception { @Override protected void doClose() throws Exception { + this.lock.lock(); + try { + this.page = 0; + this.results = null; + } + finally { + this.lock.unlock(); + } } @Override diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/data/MongoPagingItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/data/MongoPagingItemReaderTests.java index 16552fd947..3593ab49cf 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/data/MongoPagingItemReaderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/data/MongoPagingItemReaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -34,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -347,4 +349,18 @@ void testSortThrowsExceptionWhenInvokedWithNull() { .withMessage("Sorts must not be null"); } + @Test + void testClose() throws Exception { + // given + when(template.find(any(), any())).thenReturn(List.of("string")); + reader.read(); + + // when + reader.close(); + + // then + assertEquals(0, reader.page); + assertNull(reader.results); + } + } From 8165a6c93751e8d0b0588e22054b3bc4325e85e0 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 18 Dec 2024 10:34:42 +0100 Subject: [PATCH 50/55] Add note about not scoping step beans with job scope Resolves #3900 Signed-off-by: Mahmoud Ben Hassine --- spring-batch-docs/modules/ROOT/pages/step/late-binding.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-batch-docs/modules/ROOT/pages/step/late-binding.adoc b/spring-batch-docs/modules/ROOT/pages/step/late-binding.adoc index ceb0d390aa..879464ef21 100644 --- a/spring-batch-docs/modules/ROOT/pages/step/late-binding.adoc +++ b/spring-batch-docs/modules/ROOT/pages/step/late-binding.adoc @@ -201,8 +201,8 @@ The following example shows how to access the `ExecutionContext` in XML: NOTE: Any bean that uses late binding must be declared with `scope="step"`. See xref:step/late-binding.adoc#step-scope[Step Scope] for more information. -A `Step` bean should not be step-scoped. If late binding is needed in a step -definition, the components of that step (tasklet, item reader or writer, and so on) +A `Step` bean should not be step-scoped or job-scoped. If late binding is needed in a step +definition, then the components of that step (tasklet, item reade/writer, completion policy, and so on) are the ones that should be scoped instead. NOTE: If you use Spring 3.0 (or above), the expressions in step-scoped beans are in the From 095362768f38b9c262deaf8919d4dc7b92543d78 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 18 Dec 2024 12:03:46 +0100 Subject: [PATCH 51/55] Clarify wildcard usage to select input files with Java configuration Resolves #4707 Signed-off-by: Mahmoud Ben Hassine --- .../ROOT/pages/readers-and-writers/multi-file-input.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-batch-docs/modules/ROOT/pages/readers-and-writers/multi-file-input.adoc b/spring-batch-docs/modules/ROOT/pages/readers-and-writers/multi-file-input.adoc index 08307e720d..cf81b7a417 100644 --- a/spring-batch-docs/modules/ROOT/pages/readers-and-writers/multi-file-input.adoc +++ b/spring-batch-docs/modules/ROOT/pages/readers-and-writers/multi-file-input.adoc @@ -24,10 +24,10 @@ The following example shows how to read files with wildcards in Java: [source, java] ---- @Bean -public MultiResourceItemReader multiResourceReader() { +public MultiResourceItemReader multiResourceReader(@Value("classpath:data/input/file-*.txt") Resource[] resources) { return new MultiResourceItemReaderBuilder() .delegate(flatFileItemReader()) - .resources(resources()) + .resources(resources) .build(); } ---- From 7ef3d6b0b64e695f05ebb36b48537cd28f51d8db Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Wed, 18 Dec 2024 23:15:47 +0100 Subject: [PATCH 52/55] Prepare release 5.1.3 Signed-off-by: Mahmoud Ben Hassine --- pom.xml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index e6dfb5f51c..96fa4582bd 100644 --- a/pom.xml +++ b/pom.xml @@ -61,19 +61,19 @@ 17 - 6.1.7 - 2.0.6 - 6.2.5 - 1.12.6 + 6.1.16 + 2.0.11 + 6.2.11 + 1.12.12 - 3.2.6 - 3.2.6 - 3.2.6 - 4.2.6 - 3.1.5 - 3.1.5 - 3.2.3 + 3.2.12 + 3.2.12 + 3.2.12 + 4.2.12 + 3.1.10 + 3.1.8 + 3.2.9 2.15.4 1.11.3 @@ -92,7 +92,7 @@ 3.0.2 - 1.2.6 + 1.2.11 1.4.20 4.13.2 From 814f686e153a18a60434c1f2db4b8dd64a50e7e9 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Thu, 19 Dec 2024 03:59:15 +0100 Subject: [PATCH 53/55] Release version 5.1.3 --- pom.xml | 2 +- spring-batch-bom/pom.xml | 2 +- spring-batch-core/pom.xml | 2 +- spring-batch-docs/pom.xml | 2 +- spring-batch-infrastructure/pom.xml | 2 +- spring-batch-integration/pom.xml | 2 +- spring-batch-samples/pom.xml | 2 +- spring-batch-test/pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 96fa4582bd..2999d43e87 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ designed to enable the development of robust batch applications vital for the daily operations of enterprise systems. Spring Batch is part of the Spring Portfolio. - 5.1.3-SNAPSHOT + 5.1.3 pom https://projects.spring.io/spring-batch diff --git a/spring-batch-bom/pom.xml b/spring-batch-bom/pom.xml index 6043d9aad5..c0afa76edf 100644 --- a/spring-batch-bom/pom.xml +++ b/spring-batch-bom/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3-SNAPSHOT + 5.1.3 spring-batch-bom pom diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index 2e91a9a6de..b4fb686b31 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3-SNAPSHOT + 5.1.3 spring-batch-core jar diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index 60670cf4cf..1a5fe9a82e 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3-SNAPSHOT + 5.1.3 spring-batch-docs Spring Batch Docs diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml index 9e00a2e41a..17d2b09542 100644 --- a/spring-batch-infrastructure/pom.xml +++ b/spring-batch-infrastructure/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3-SNAPSHOT + 5.1.3 spring-batch-infrastructure jar diff --git a/spring-batch-integration/pom.xml b/spring-batch-integration/pom.xml index 78f03aae3f..c898444325 100644 --- a/spring-batch-integration/pom.xml +++ b/spring-batch-integration/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3-SNAPSHOT + 5.1.3 spring-batch-integration Spring Batch Integration diff --git a/spring-batch-samples/pom.xml b/spring-batch-samples/pom.xml index cb71fb62d0..3253aa4d61 100644 --- a/spring-batch-samples/pom.xml +++ b/spring-batch-samples/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3-SNAPSHOT + 5.1.3 spring-batch-samples jar diff --git a/spring-batch-test/pom.xml b/spring-batch-test/pom.xml index 7cba0d1104..e2baa36088 100644 --- a/spring-batch-test/pom.xml +++ b/spring-batch-test/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3-SNAPSHOT + 5.1.3 spring-batch-test Spring Batch Test From 3cfabdbf3bea743c6d29965c242d343bd52a367e Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Fri, 20 Dec 2024 09:53:46 +0100 Subject: [PATCH 54/55] Next development version --- pom.xml | 2 +- spring-batch-bom/pom.xml | 2 +- spring-batch-core/pom.xml | 2 +- spring-batch-docs/pom.xml | 2 +- spring-batch-infrastructure/pom.xml | 2 +- spring-batch-integration/pom.xml | 2 +- spring-batch-samples/pom.xml | 2 +- spring-batch-test/pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 2999d43e87..a3bbb89e16 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ designed to enable the development of robust batch applications vital for the daily operations of enterprise systems. Spring Batch is part of the Spring Portfolio. - 5.1.3 + 5.1.4-SNAPSHOT pom https://projects.spring.io/spring-batch diff --git a/spring-batch-bom/pom.xml b/spring-batch-bom/pom.xml index c0afa76edf..0ce9333623 100644 --- a/spring-batch-bom/pom.xml +++ b/spring-batch-bom/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3 + 5.1.4-SNAPSHOT spring-batch-bom pom diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index b4fb686b31..c3499ed214 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3 + 5.1.4-SNAPSHOT spring-batch-core jar diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index 1a5fe9a82e..e47753796e 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3 + 5.1.4-SNAPSHOT spring-batch-docs Spring Batch Docs diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml index 17d2b09542..fe1199d193 100644 --- a/spring-batch-infrastructure/pom.xml +++ b/spring-batch-infrastructure/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3 + 5.1.4-SNAPSHOT spring-batch-infrastructure jar diff --git a/spring-batch-integration/pom.xml b/spring-batch-integration/pom.xml index c898444325..01a2455634 100644 --- a/spring-batch-integration/pom.xml +++ b/spring-batch-integration/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3 + 5.1.4-SNAPSHOT spring-batch-integration Spring Batch Integration diff --git a/spring-batch-samples/pom.xml b/spring-batch-samples/pom.xml index 3253aa4d61..4e19857bab 100644 --- a/spring-batch-samples/pom.xml +++ b/spring-batch-samples/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3 + 5.1.4-SNAPSHOT spring-batch-samples jar diff --git a/spring-batch-test/pom.xml b/spring-batch-test/pom.xml index e2baa36088..03ed39b9a9 100644 --- a/spring-batch-test/pom.xml +++ b/spring-batch-test/pom.xml @@ -4,7 +4,7 @@ org.springframework.batch spring-batch - 5.1.3 + 5.1.4-SNAPSHOT spring-batch-test Spring Batch Test From 1cbd385b49241737802deae17e6eb35524e2e0b4 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Fri, 27 Sep 2024 10:08:38 +0200 Subject: [PATCH 55/55] Update docker image version in SQLServerJobRepositoryIntegrationTests (cherry picked from commit 11ee2fe22a3e133a67ce5c1ad6a8105d952177a1) --- .../repository/SQLServerJobRepositoryIntegrationTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLServerJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLServerJobRepositoryIntegrationTests.java index 304c7abc66..b8373688f1 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLServerJobRepositoryIntegrationTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLServerJobRepositoryIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 the original author or authors. + * Copyright 2020-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,7 +58,7 @@ class SQLServerJobRepositoryIntegrationTests { // TODO find the best way to externalize and manage image versions private static final DockerImageName SQLSERVER_IMAGE = DockerImageName - .parse("mcr.microsoft.com/mssql/server:2019-CU11-ubuntu-20.04"); + .parse("mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04"); @Container public static MSSQLServerContainer sqlserver = new MSSQLServerContainer<>(SQLSERVER_IMAGE).acceptLicense();