From ae681f85c480c606e1064c85bb0fe5614806f39b Mon Sep 17 00:00:00 2001 From: asmhatre Date: Mon, 28 Sep 2026 09:09:50 +0000 Subject: [PATCH] Add batch-5-to-6 module: Spring Batch 5.2 to 6.0 migration on Boot 3.5 to 4.1 Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01Gth99spB1CzQmBFofXmU4Z --- batch-5-to-6/.gitignore | 1 + batch-5-to-6/README.md | 13 ++++ batch-5-to-6/legacy/pom.xml | 21 ++++++ .../src/main/java/com/ankurm/batch/App.java | 14 ++++ .../java/com/ankurm/batch/BatchConfig.java | 55 +++++++++++++++ .../main/java/com/ankurm/batch/JobRunner.java | 33 +++++++++ .../src/main/resources/application.properties | 3 + .../test/java/com/ankurm/batch/JobTest.java | 23 +++++++ batch-5-to-6/migrated/pom.xml | 22 ++++++ .../src/main/java/com/ankurm/batch/App.java | 14 ++++ .../java/com/ankurm/batch/BatchConfig.java | 56 +++++++++++++++ .../main/java/com/ankurm/batch/JobRunner.java | 33 +++++++++ .../src/main/resources/application.properties | 3 + .../test/java/com/ankurm/batch/JobTest.java | 23 +++++++ batch-5-to-6/output/01-legacy-batch5.txt | 15 ++++ .../output/02-compile-errors-after-bump.txt | 10 +++ ...-imports-ported-no-transaction-manager.txt | 19 +++++ batch-5-to-6/output/04-jdbc-starter-added.txt | 23 +++++++ .../05-new-chunk-api-listener-silent.txt | 17 +++++ batch-5-to-6/output/06-migrated.txt | 15 ++++ batch-5-to-6/output/07-api-facts.txt | 13 ++++ batch-5-to-6/scripts/run-all.sh | 69 +++++++++++++++++++ 22 files changed, 495 insertions(+) create mode 100644 batch-5-to-6/.gitignore create mode 100644 batch-5-to-6/README.md create mode 100644 batch-5-to-6/legacy/pom.xml create mode 100644 batch-5-to-6/legacy/src/main/java/com/ankurm/batch/App.java create mode 100644 batch-5-to-6/legacy/src/main/java/com/ankurm/batch/BatchConfig.java create mode 100644 batch-5-to-6/legacy/src/main/java/com/ankurm/batch/JobRunner.java create mode 100644 batch-5-to-6/legacy/src/main/resources/application.properties create mode 100644 batch-5-to-6/legacy/src/test/java/com/ankurm/batch/JobTest.java create mode 100644 batch-5-to-6/migrated/pom.xml create mode 100644 batch-5-to-6/migrated/src/main/java/com/ankurm/batch/App.java create mode 100644 batch-5-to-6/migrated/src/main/java/com/ankurm/batch/BatchConfig.java create mode 100644 batch-5-to-6/migrated/src/main/java/com/ankurm/batch/JobRunner.java create mode 100644 batch-5-to-6/migrated/src/main/resources/application.properties create mode 100644 batch-5-to-6/migrated/src/test/java/com/ankurm/batch/JobTest.java create mode 100644 batch-5-to-6/output/01-legacy-batch5.txt create mode 100644 batch-5-to-6/output/02-compile-errors-after-bump.txt create mode 100644 batch-5-to-6/output/03-imports-ported-no-transaction-manager.txt create mode 100644 batch-5-to-6/output/04-jdbc-starter-added.txt create mode 100644 batch-5-to-6/output/05-new-chunk-api-listener-silent.txt create mode 100644 batch-5-to-6/output/06-migrated.txt create mode 100644 batch-5-to-6/output/07-api-facts.txt create mode 100755 batch-5-to-6/scripts/run-all.sh diff --git a/batch-5-to-6/.gitignore b/batch-5-to-6/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/batch-5-to-6/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/batch-5-to-6/README.md b/batch-5-to-6/README.md new file mode 100644 index 0000000..941783a --- /dev/null +++ b/batch-5-to-6/README.md @@ -0,0 +1,13 @@ +# batch-5-to-6: Spring Batch 5 to 6 on Spring Boot 3.5 to 4.1 + +Companion code for the ankurm.com post "Spring Batch 5 to 6 Migration Guide". + +| Folder | What it is | +|---|---| +| `legacy/` | A one-job app on Boot 3.5.16 / Batch 5.2.6 (JDK 21) using the Batch 5 API | +| `migrated/` | The same app on Boot 4.1.1 / Batch 6.0.5 (JDK 25) using the Batch 6 API | +| `scripts/run-all.sh` | Builds the intermediate stages from `legacy/` and regenerates every file in `output/` | +| `output/` | Transcripts: compile errors, startup failure, deprecation warnings, the silent listener change, and the final run | + +Batch 6.0.5 is the latest GA; 6.1.0-M1 and 6.1.0-M2 are milestones and are not tested here. +Tested on 28 September 2026. diff --git a/batch-5-to-6/legacy/pom.xml b/batch-5-to-6/legacy/pom.xml new file mode 100644 index 0000000..20adc7d --- /dev/null +++ b/batch-5-to-6/legacy/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.5.16 + + + com.ankurm + batch-legacy + 1.0.0 + 21 + + org.springframework.bootspring-boot-starter-batch + com.h2databaseh2runtime + org.springframework.bootspring-boot-starter-testtest + org.springframework.batchspring-batch-testtest + + org.springframework.bootspring-boot-maven-plugin + diff --git a/batch-5-to-6/legacy/src/main/java/com/ankurm/batch/App.java b/batch-5-to-6/legacy/src/main/java/com/ankurm/batch/App.java new file mode 100644 index 0000000..23500d9 --- /dev/null +++ b/batch-5-to-6/legacy/src/main/java/com/ankurm/batch/App.java @@ -0,0 +1,14 @@ +package com.ankurm.batch; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; + +@SpringBootApplication +public class App { + public static void main(String[] args) { + ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args); + ctx.getBean(JobRunner.class).run(); + ctx.close(); + } +} diff --git a/batch-5-to-6/legacy/src/main/java/com/ankurm/batch/BatchConfig.java b/batch-5-to-6/legacy/src/main/java/com/ankurm/batch/BatchConfig.java new file mode 100644 index 0000000..7c4c588 --- /dev/null +++ b/batch-5-to-6/legacy/src/main/java/com/ankurm/batch/BatchConfig.java @@ -0,0 +1,55 @@ +package com.ankurm.batch; + +import java.util.List; +import org.springframework.batch.core.ChunkListener; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.support.ListItemReader; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; + +@Configuration +public class BatchConfig { + + @Bean + ItemReader reader() { + return new ListItemReader<>(List.of(1, 2, 3, 4, 5, 6, 7)); + } + + @Bean + ItemWriter writer() { + return chunk -> System.out.println("WRITE " + chunk.getItems()); + } + + @Bean + ChunkListener chunkListener() { + return new ChunkListener() { + @Override public void afterChunk(ChunkContext context) { + System.out.println("CHUNK DONE, read so far=" + context.getStepContext().getStepExecution().getReadCount()); + } + }; + } + + @Bean + Step squareStep(JobRepository repo, PlatformTransactionManager tx, ChunkListener listener) { + return new StepBuilder("squareStep", repo) + .chunk(3, tx) + .reader(reader()) + .processor(i -> "sq" + (i * i)) + .writer(writer()) + .listener(listener) + .build(); + } + + @Bean + Job squareJob(JobRepository repo, Step squareStep) { + return new JobBuilder("squareJob", repo).start(squareStep).build(); + } +} diff --git a/batch-5-to-6/legacy/src/main/java/com/ankurm/batch/JobRunner.java b/batch-5-to-6/legacy/src/main/java/com/ankurm/batch/JobRunner.java new file mode 100644 index 0000000..ace3fe2 --- /dev/null +++ b/batch-5-to-6/legacy/src/main/java/com/ankurm/batch/JobRunner.java @@ -0,0 +1,33 @@ +package com.ankurm.batch; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.stereotype.Component; + +@Component +public class JobRunner { + private final JobLauncher launcher; + private final JobExplorer explorer; + private final Job job; + + public JobRunner(JobLauncher launcher, JobExplorer explorer, Job squareJob) { + this.launcher = launcher; this.explorer = explorer; this.job = squareJob; + } + + public void run() { + try { + JobParameters params = new JobParametersBuilder().addLong("run.id", 1L).toJobParameters(); + JobExecution exec = launcher.run(job, params); + System.out.println("STATUS " + exec.getStatus() + " exit=" + exec.getExitStatus().getExitCode()); + System.out.println("INSTANCES " + explorer.getJobInstanceCount("squareJob")); + System.out.println("DONE " + (exec.getStatus() == BatchStatus.COMPLETED)); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} diff --git a/batch-5-to-6/legacy/src/main/resources/application.properties b/batch-5-to-6/legacy/src/main/resources/application.properties new file mode 100644 index 0000000..b08183f --- /dev/null +++ b/batch-5-to-6/legacy/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.batch.job.enabled=false +spring.datasource.url=jdbc:h2:mem:legacy;DB_CLOSE_DELAY=-1 +spring.batch.jdbc.initialize-schema=always diff --git a/batch-5-to-6/legacy/src/test/java/com/ankurm/batch/JobTest.java b/batch-5-to-6/legacy/src/test/java/com/ankurm/batch/JobTest.java new file mode 100644 index 0000000..4097ca2 --- /dev/null +++ b/batch-5-to-6/legacy/src/test/java/com/ankurm/batch/JobTest.java @@ -0,0 +1,23 @@ +package com.ankurm.batch; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.batch.test.context.SpringBatchTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +@SpringBatchTest +class JobTest { + @Autowired JobLauncherTestUtils utils; + + @Test + void jobCompletes() throws Exception { + JobExecution exec = utils.launchJob(); + assertThat(exec.getStatus()).isEqualTo(BatchStatus.COMPLETED); + } +} diff --git a/batch-5-to-6/migrated/pom.xml b/batch-5-to-6/migrated/pom.xml new file mode 100644 index 0000000..03c0446 --- /dev/null +++ b/batch-5-to-6/migrated/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 4.1.1 + + + com.ankurm + batch-migrated + 1.0.0 + 25 + + org.springframework.bootspring-boot-starter-batch-jdbc + org.springframework.bootspring-boot-starter-jdbc + com.h2databaseh2runtime + org.springframework.bootspring-boot-starter-testtest + org.springframework.batchspring-batch-testtest + + org.springframework.bootspring-boot-maven-plugin + diff --git a/batch-5-to-6/migrated/src/main/java/com/ankurm/batch/App.java b/batch-5-to-6/migrated/src/main/java/com/ankurm/batch/App.java new file mode 100644 index 0000000..23500d9 --- /dev/null +++ b/batch-5-to-6/migrated/src/main/java/com/ankurm/batch/App.java @@ -0,0 +1,14 @@ +package com.ankurm.batch; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; + +@SpringBootApplication +public class App { + public static void main(String[] args) { + ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args); + ctx.getBean(JobRunner.class).run(); + ctx.close(); + } +} diff --git a/batch-5-to-6/migrated/src/main/java/com/ankurm/batch/BatchConfig.java b/batch-5-to-6/migrated/src/main/java/com/ankurm/batch/BatchConfig.java new file mode 100644 index 0000000..6e7a3cf --- /dev/null +++ b/batch-5-to-6/migrated/src/main/java/com/ankurm/batch/BatchConfig.java @@ -0,0 +1,56 @@ +package com.ankurm.batch; + +import java.util.List; +import org.springframework.batch.core.listener.ChunkListener; +import org.springframework.batch.core.job.Job; +import org.springframework.batch.core.step.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.infrastructure.item.Chunk; +import org.springframework.batch.infrastructure.item.ItemReader; +import org.springframework.batch.infrastructure.item.ItemWriter; +import org.springframework.batch.infrastructure.item.support.ListItemReader; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; + +@Configuration +public class BatchConfig { + + @Bean + ItemReader reader() { + return new ListItemReader<>(List.of(1, 2, 3, 4, 5, 6, 7)); + } + + @Bean + ItemWriter writer() { + return chunk -> System.out.println("WRITE " + chunk.getItems()); + } + + @Bean + ChunkListener chunkListener() { + return new ChunkListener<>() { + @Override public void afterChunk(Chunk chunk) { + System.out.println("CHUNK DONE, items in chunk=" + chunk.size()); + } + }; + } + + @Bean + Step squareStep(JobRepository repo, PlatformTransactionManager tx, ChunkListener listener) { + return new StepBuilder("squareStep", repo) + .chunk(3) + .transactionManager(tx) + .reader(reader()) + .processor(i -> "sq" + (i * i)) + .writer(writer()) + .listener(listener) + .build(); + } + + @Bean + Job squareJob(JobRepository repo, Step squareStep) { + return new JobBuilder("squareJob", repo).start(squareStep).build(); + } +} diff --git a/batch-5-to-6/migrated/src/main/java/com/ankurm/batch/JobRunner.java b/batch-5-to-6/migrated/src/main/java/com/ankurm/batch/JobRunner.java new file mode 100644 index 0000000..3fcfa2b --- /dev/null +++ b/batch-5-to-6/migrated/src/main/java/com/ankurm/batch/JobRunner.java @@ -0,0 +1,33 @@ +package com.ankurm.batch; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.job.Job; +import org.springframework.batch.core.job.JobExecution; +import org.springframework.batch.core.job.parameters.JobParameters; +import org.springframework.batch.core.job.parameters.JobParametersBuilder; +import org.springframework.batch.core.launch.JobOperator; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.stereotype.Component; + +@Component +public class JobRunner { + private final JobOperator operator; + private final JobRepository repository; + private final Job job; + + public JobRunner(JobOperator operator, JobRepository repository, Job squareJob) { + this.operator = operator; this.repository = repository; this.job = squareJob; + } + + public void run() { + try { + JobParameters params = new JobParametersBuilder().addLong("run.id", 1L).toJobParameters(); + JobExecution exec = operator.start(job, params); + System.out.println("STATUS " + exec.getStatus() + " exit=" + exec.getExitStatus().getExitCode()); + System.out.println("INSTANCES " + repository.getJobInstanceCount("squareJob")); + System.out.println("DONE " + (exec.getStatus() == BatchStatus.COMPLETED)); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} diff --git a/batch-5-to-6/migrated/src/main/resources/application.properties b/batch-5-to-6/migrated/src/main/resources/application.properties new file mode 100644 index 0000000..b08183f --- /dev/null +++ b/batch-5-to-6/migrated/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.batch.job.enabled=false +spring.datasource.url=jdbc:h2:mem:legacy;DB_CLOSE_DELAY=-1 +spring.batch.jdbc.initialize-schema=always diff --git a/batch-5-to-6/migrated/src/test/java/com/ankurm/batch/JobTest.java b/batch-5-to-6/migrated/src/test/java/com/ankurm/batch/JobTest.java new file mode 100644 index 0000000..4320bf3 --- /dev/null +++ b/batch-5-to-6/migrated/src/test/java/com/ankurm/batch/JobTest.java @@ -0,0 +1,23 @@ +package com.ankurm.batch; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.job.JobExecution; +import org.springframework.batch.test.JobOperatorTestUtils; +import org.springframework.batch.test.context.SpringBatchTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +@SpringBatchTest +class JobTest { + @Autowired JobOperatorTestUtils utils; + + @Test + void jobCompletes() throws Exception { + JobExecution exec = utils.startJob(); + assertThat(exec.getStatus()).isEqualTo(BatchStatus.COMPLETED); + } +} diff --git a/batch-5-to-6/output/01-legacy-batch5.txt b/batch-5-to-6/output/01-legacy-batch5.txt new file mode 100644 index 0000000..93db312 --- /dev/null +++ b/batch-5-to-6/output/01-legacy-batch5.txt @@ -0,0 +1,15 @@ +$ mvn test # Boot 3.5.16, Batch 5.2.6, JDK 21 +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.750 s -- in com.ankurm.batch.JobTest +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 +[INFO] BUILD SUCCESS + +$ java -jar target/batch-legacy-1.0.0.jar +WRITE [sq1, sq4, sq9] +CHUNK DONE, read so far=3 +WRITE [sq16, sq25, sq36] +CHUNK DONE, read so far=6 +WRITE [sq49] +CHUNK DONE, read so far=7 +STATUS COMPLETED exit=COMPLETED +INSTANCES 1 +DONE true diff --git a/batch-5-to-6/output/02-compile-errors-after-bump.txt b/batch-5-to-6/output/02-compile-errors-after-bump.txt new file mode 100644 index 0000000..ef16317 --- /dev/null +++ b/batch-5-to-6/output/02-compile-errors-after-bump.txt @@ -0,0 +1,10 @@ +$ mvn compile # legacy sources, only the Boot version changed to 4.1.1 (Batch 6.0.5) +compile error lines reported: 56 + +packages that no longer exist: +package org.springframework.batch.core.explore does not exist +package org.springframework.batch.item does not exist +package org.springframework.batch.item.support does not exist + +classes that moved: +ChunkListener ItemReader ItemWriter Job JobExecution JobExplorer JobParameters JobParametersBuilder ListItemReader Step diff --git a/batch-5-to-6/output/03-imports-ported-no-transaction-manager.txt b/batch-5-to-6/output/03-imports-ported-no-transaction-manager.txt new file mode 100644 index 0000000..b4d0c03 --- /dev/null +++ b/batch-5-to-6/output/03-imports-ported-no-transaction-manager.txt @@ -0,0 +1,19 @@ +$ mvn package # imports ported to the new packages, dependencies unchanged (spring-boot-starter-batch) +[WARNING] s2/src/main/java/com/ankurm/batch/BatchConfig.java:[34,35] afterChunk(org.springframework.batch.core.scope.context.ChunkContext) in org.springframework.batch.core.listener.ChunkListener has been deprecated and marked for removal +[WARNING] s2/src/main/java/com/ankurm/batch/BatchConfig.java:[43,17] chunk(int,org.springframework.transaction.PlatformTransactionManager) in org.springframework.batch.core.step.builder.StepBuilder has been deprecated and marked for removal +[WARNING] s2/src/main/java/com/ankurm/batch/JobRunner.java:[14,19] org.springframework.batch.core.launch.JobLauncher in org.springframework.batch.core.launch has been deprecated and marked for removal +[WARNING] s2/src/main/java/com/ankurm/batch/JobRunner.java:[15,19] org.springframework.batch.core.repository.explore.JobExplorer in org.springframework.batch.core.repository.explore has been deprecated and marked for removal +[WARNING] s2/src/main/java/com/ankurm/batch/JobRunner.java:[18,22] org.springframework.batch.core.launch.JobLauncher in org.springframework.batch.core.launch has been deprecated and marked for removal +[WARNING] s2/src/main/java/com/ankurm/batch/JobRunner.java:[18,44] org.springframework.batch.core.repository.explore.JobExplorer in org.springframework.batch.core.repository.explore has been deprecated and marked for removal +[WARNING] s2/src/test/java/com/ankurm/batch/JobTest.java:[16,16] org.springframework.batch.test.JobLauncherTestUtils in org.springframework.batch.test has been deprecated and marked for removal +[WARNING] s2/src/test/java/com/ankurm/batch/JobTest.java:[20,34] launchJob() in org.springframework.batch.test.JobLauncherTestUtils has been deprecated and marked for removal +[INFO] BUILD SUCCESS + +$ java -jar target/batch-legacy-1.0.0.jar +APPLICATION FAILED TO START +*************************** + +Description: + +Parameter 1 of method squareStep in com.ankurm.batch.BatchConfig required a bean of type 'org.springframework.transaction.PlatformTransactionManager' that could not be found. + diff --git a/batch-5-to-6/output/04-jdbc-starter-added.txt b/batch-5-to-6/output/04-jdbc-starter-added.txt new file mode 100644 index 0000000..4f2448b --- /dev/null +++ b/batch-5-to-6/output/04-jdbc-starter-added.txt @@ -0,0 +1,23 @@ +$ mvn package # + spring-boot-starter-batch-jdbc and spring-boot-starter-jdbc +[WARNING] s3/src/main/java/com/ankurm/batch/BatchConfig.java:[34,35] afterChunk(org.springframework.batch.core.scope.context.ChunkContext) in org.springframework.batch.core.listener.ChunkListener has been deprecated and marked for removal +[WARNING] s3/src/main/java/com/ankurm/batch/BatchConfig.java:[43,17] chunk(int,org.springframework.transaction.PlatformTransactionManager) in org.springframework.batch.core.step.builder.StepBuilder has been deprecated and marked for removal +[WARNING] s3/src/main/java/com/ankurm/batch/JobRunner.java:[14,19] org.springframework.batch.core.launch.JobLauncher in org.springframework.batch.core.launch has been deprecated and marked for removal +[WARNING] s3/src/main/java/com/ankurm/batch/JobRunner.java:[15,19] org.springframework.batch.core.repository.explore.JobExplorer in org.springframework.batch.core.repository.explore has been deprecated and marked for removal +[WARNING] s3/src/main/java/com/ankurm/batch/JobRunner.java:[18,22] org.springframework.batch.core.launch.JobLauncher in org.springframework.batch.core.launch has been deprecated and marked for removal +[WARNING] s3/src/main/java/com/ankurm/batch/JobRunner.java:[18,44] org.springframework.batch.core.repository.explore.JobExplorer in org.springframework.batch.core.repository.explore has been deprecated and marked for removal +[WARNING] s3/src/test/java/com/ankurm/batch/JobTest.java:[16,16] org.springframework.batch.test.JobLauncherTestUtils in org.springframework.batch.test has been deprecated and marked for removal +[WARNING] s3/src/test/java/com/ankurm/batch/JobTest.java:[20,34] launchJob() in org.springframework.batch.test.JobLauncherTestUtils has been deprecated and marked for removal +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.571 s -- in com.ankurm.batch.JobTest +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 +[INFO] BUILD SUCCESS + +$ java -jar target/batch-legacy-1.0.0.jar +WRITE [sq1, sq4, sq9] +CHUNK DONE, read so far=3 +WRITE [sq16, sq25, sq36] +CHUNK DONE, read so far=6 +WRITE [sq49] +CHUNK DONE, read so far=7 +STATUS COMPLETED exit=COMPLETED +INSTANCES 1 +DONE true diff --git a/batch-5-to-6/output/05-new-chunk-api-listener-silent.txt b/batch-5-to-6/output/05-new-chunk-api-listener-silent.txt new file mode 100644 index 0000000..a416498 --- /dev/null +++ b/batch-5-to-6/output/05-new-chunk-api-listener-silent.txt @@ -0,0 +1,17 @@ +$ mvn package # chunk(3, tx) replaced by chunk(3).transactionManager(tx); listener untouched +[WARNING] s4/src/main/java/com/ankurm/batch/BatchConfig.java:[34,35] afterChunk(org.springframework.batch.core.scope.context.ChunkContext) in org.springframework.batch.core.listener.ChunkListener has been deprecated and marked for removal +[WARNING] s4/src/main/java/com/ankurm/batch/JobRunner.java:[14,19] org.springframework.batch.core.launch.JobLauncher in org.springframework.batch.core.launch has been deprecated and marked for removal +[WARNING] s4/src/main/java/com/ankurm/batch/JobRunner.java:[15,19] org.springframework.batch.core.repository.explore.JobExplorer in org.springframework.batch.core.repository.explore has been deprecated and marked for removal +[WARNING] s4/src/main/java/com/ankurm/batch/JobRunner.java:[18,22] org.springframework.batch.core.launch.JobLauncher in org.springframework.batch.core.launch has been deprecated and marked for removal +[WARNING] s4/src/main/java/com/ankurm/batch/JobRunner.java:[18,44] org.springframework.batch.core.repository.explore.JobExplorer in org.springframework.batch.core.repository.explore has been deprecated and marked for removal +[WARNING] s4/src/test/java/com/ankurm/batch/JobTest.java:[16,16] org.springframework.batch.test.JobLauncherTestUtils in org.springframework.batch.test has been deprecated and marked for removal +[WARNING] s4/src/test/java/com/ankurm/batch/JobTest.java:[20,34] launchJob() in org.springframework.batch.test.JobLauncherTestUtils has been deprecated and marked for removal +[INFO] BUILD SUCCESS + +$ java -jar target/batch-legacy-1.0.0.jar +WRITE [sq1, sq4, sq9] +WRITE [sq16, sq25, sq36] +WRITE [sq49] +STATUS COMPLETED exit=COMPLETED +INSTANCES 1 +DONE true diff --git a/batch-5-to-6/output/06-migrated.txt b/batch-5-to-6/output/06-migrated.txt new file mode 100644 index 0000000..4f48a52 --- /dev/null +++ b/batch-5-to-6/output/06-migrated.txt @@ -0,0 +1,15 @@ +$ mvn package # final migrated project +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.029 s -- in com.ankurm.batch.JobTest +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 +[INFO] BUILD SUCCESS + +$ java -jar target/batch-migrated-1.0.0.jar +WRITE [sq1, sq4, sq9] +CHUNK DONE, items in chunk=3 +WRITE [sq16, sq25, sq36] +CHUNK DONE, items in chunk=3 +WRITE [sq49] +CHUNK DONE, items in chunk=1 +STATUS COMPLETED exit=COMPLETED +INSTANCES 1 +DONE true diff --git a/batch-5-to-6/output/07-api-facts.txt b/batch-5-to-6/output/07-api-facts.txt new file mode 100644 index 0000000..3fb2335 --- /dev/null +++ b/batch-5-to-6/output/07-api-facts.txt @@ -0,0 +1,13 @@ +$ javap (Batch 6.0.5 jars), selected lines +public interface core.launch.JobOperator extends core.launch.JobLauncher { +public interface core.repository.JobRepository extends core.repository.explore.JobExplorer { +public class test.JobOperatorTestUtils extends test.JobLauncherTestUtils { + public core.step.builder.SimpleStepBuilder chunk(int, PlatformTransactionManager); + public core.step.builder.ChunkOrientedStepBuilder chunk(int); + public core.step.builder.SimpleStepBuilder chunk(infrastructure.repeat.CompletionPolicy, PlatformTransactionManager); + public default void beforeChunk(core.scope.context.ChunkContext); + public default void afterChunk(core.scope.context.ChunkContext); + public default void afterChunkError(core.scope.context.ChunkContext); + public default void beforeChunk(infrastructure.item.Chunk); + public default void afterChunk(infrastructure.item.Chunk); + public default void onChunkError(java.lang.Exception, infrastructure.item.Chunk); diff --git a/batch-5-to-6/scripts/run-all.sh b/batch-5-to-6/scripts/run-all.sh new file mode 100755 index 0000000..91c5739 --- /dev/null +++ b/batch-5-to-6/scripts/run-all.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# Regenerates output/*.txt. Needs Maven, JDK 21 (J21) and JDK 25 (J25); network for Maven Central. +set -u +HERE=$(cd "$(dirname "$0")/.." && pwd); OUT=$HERE/output; W=${WORK:-/tmp/b56-work} +J21=${J21:-/usr/lib/jvm/java-21-openjdk-amd64}; J25=${J25:-/tmp/tools/jdk-25.0.4.1+1}; MVN=${MVN:-mvn} +mkdir -p "$OUT"; rm -rf "$W"; mkdir -p "$W" +mv_() { local jh=$1 d=$2; shift 2; (cd "$d" && JAVA_HOME=$jh $MVN -B -Dmaven.compiler.showDeprecation=true "$@" 2>&1 | grep -v JAVA_TOOL_OPTIONS | sed "s#$W/##g"); } +runjar() { local jh=$1 jar=$2; JAVA_HOME=$jh $jh/bin/java -jar "$jar" 2>&1 | grep -E '^(WRITE|CHUNK|STATUS|INSTANCES|DONE)'; } +stage() { rm -rf "$W/$1"; cp -r "$HERE/$2" "$W/$1"; rm -rf "$W/$1/target"; } +PORT_IMPORTS=$(cat <<'PY' +import glob,sys +m={'org.springframework.batch.core.ChunkListener':'org.springframework.batch.core.listener.ChunkListener', +'org.springframework.batch.core.Job;':'org.springframework.batch.core.job.Job;', +'org.springframework.batch.core.Step;':'org.springframework.batch.core.step.Step;', +'org.springframework.batch.core.JobExecution;':'org.springframework.batch.core.job.JobExecution;', +'org.springframework.batch.core.JobParameters;':'org.springframework.batch.core.job.parameters.JobParameters;', +'org.springframework.batch.core.JobParametersBuilder':'org.springframework.batch.core.job.parameters.JobParametersBuilder', +'org.springframework.batch.core.explore.JobExplorer':'org.springframework.batch.core.repository.explore.JobExplorer', +'org.springframework.batch.item.':'org.springframework.batch.infrastructure.item.'} +for f in glob.glob(sys.argv[1]+'/src/**/*.java',recursive=True): + s=open(f).read() + for a,b in m.items(): s=s.replace(a,b) + open(f,'w').write(s) +PY +) +# 01 legacy: Boot 3.5.16 / Batch 5.2.6 +stage s0 legacy +{ echo '$ mvn test # Boot 3.5.16, Batch 5.2.6, JDK 21'; mv_ "$J21" "$W/s0" package | grep -E 'Tests run:|BUILD' + echo; echo '$ java -jar target/batch-legacy-1.0.0.jar'; runjar "$J21" "$W/s0/target/batch-legacy-1.0.0.jar"; } > "$OUT/01-legacy-batch5.txt" +# 02 same sources, Boot 4.1.1 +stage s1 legacy; sed -i 's/3.5.16/4.1.1/; s/21/25/' "$W/s1/pom.xml" +{ echo '$ mvn compile # legacy sources, only the Boot version changed to 4.1.1 (Batch 6.0.5)' + mv_ "$J25" "$W/s1" compile > "$W/s1.log" + echo "compile error lines reported: $(grep -c '^\[ERROR\] .*\.java' "$W/s1.log")"; echo; echo 'packages that no longer exist:' + grep -oE 'package [a-z.]+ does not exist' "$W/s1.log" | sort -u; echo; echo 'classes that moved:' + grep -oE 'symbol: +class [A-Za-z]+' "$W/s1.log" | awk '{print $3}' | sort -u | tr '\n' ' '; echo; } > "$OUT/02-compile-errors-after-bump.txt" +# 03 imports ported, dependencies untouched +cp -r "$W/s1" "$W/s2"; rm -rf "$W/s2/target"; python3 -c "$PORT_IMPORTS" "$W/s2" +{ echo '$ mvn package # imports ported to the new packages, dependencies unchanged (spring-boot-starter-batch)' + mv_ "$J25" "$W/s2" -DskipTests package | grep -E 'WARNING.*\.java|BUILD|ERROR.*\.java' + echo; echo '$ java -jar target/batch-legacy-1.0.0.jar' + JAVA_HOME=$J25 $J25/bin/java -jar "$W/s2/target/batch-legacy-1.0.0.jar" 2>&1 | grep -A6 'APPLICATION FAILED'; } > "$OUT/03-imports-ported-no-transaction-manager.txt" +# 04 + JDBC starter +cp -r "$W/s2" "$W/s3"; rm -rf "$W/s3/target"; python3 - "$W/s3/pom.xml" <<'PY' +import sys; p=sys.argv[1]; s=open(p).read() +s=s.replace('spring-boot-starter-batch','spring-boot-starter-batch-jdbc\n org.springframework.bootspring-boot-starter-jdbc') +open(p,'w').write(s) +PY +{ echo '$ mvn package # + spring-boot-starter-batch-jdbc and spring-boot-starter-jdbc' + mv_ "$J25" "$W/s3" package | grep -E 'WARNING.*\.java|Tests run:|BUILD' + echo; echo '$ java -jar target/batch-legacy-1.0.0.jar'; runjar "$J25" "$W/s3/target/batch-legacy-1.0.0.jar"; } > "$OUT/04-jdbc-starter-added.txt" +# 05 new chunk API but old listener +cp -r "$W/s3" "$W/s4"; rm -rf "$W/s4/target"; sed -i 's/\.chunk(3, tx)/.chunk(3)\n .transactionManager(tx)/' "$W/s4/src/main/java/com/ankurm/batch/BatchConfig.java" +{ echo '$ mvn package # chunk(3, tx) replaced by chunk(3).transactionManager(tx); listener untouched' + mv_ "$J25" "$W/s4" -DskipTests package | grep -E 'WARNING.*\.java|BUILD|ERROR.*\.java' + echo; echo '$ java -jar target/batch-legacy-1.0.0.jar'; runjar "$J25" "$W/s4/target/batch-legacy-1.0.0.jar"; } > "$OUT/05-new-chunk-api-listener-silent.txt" +# 06 final migrated +stage m migrated +{ echo '$ mvn package # final migrated project' + mv_ "$J25" "$W/m" package | grep -E 'WARNING.*\.java|Tests run:|BUILD' + echo; echo '$ java -jar target/batch-migrated-1.0.0.jar'; runjar "$J25" "$W/m/target/batch-migrated-1.0.0.jar"; } > "$OUT/06-migrated.txt" +# 07 API facts from the jars +M2=${M2:-$HOME/.m2/repository/org/springframework/batch} +CP=$M2/spring-batch-core/6.0.5/spring-batch-core-6.0.5.jar:$M2/spring-batch-infrastructure/6.0.5/spring-batch-infrastructure-6.0.5.jar:$M2/spring-batch-test/6.0.5/spring-batch-test-6.0.5.jar +{ echo '$ javap (Batch 6.0.5 jars), selected lines' + for c in org.springframework.batch.core.launch.JobOperator org.springframework.batch.core.repository.JobRepository org.springframework.batch.test.JobOperatorTestUtils; do env -u JAVA_TOOL_OPTIONS $J25/bin/javap -cp $CP $c 2>&1 | grep -E '^public (interface|class)' | sed 's/org\.springframework\.batch\.//g'; done + env -u JAVA_TOOL_OPTIONS $J25/bin/javap -cp $CP org.springframework.batch.core.step.builder.StepBuilder 2>&1 | grep -E ' chunk\(' | sed 's/org\.springframework\.batch\.//g; s/org\.springframework\.transaction\.//g; s/org\.springframework\.//g' + env -u JAVA_TOOL_OPTIONS $J25/bin/javap -cp $CP org.springframework.batch.core.listener.ChunkListener 2>&1 | grep -E 'Chunk(Context|<)' | sed 's/org\.springframework\.batch\.//g'; } > "$OUT/07-api-facts.txt" +echo done