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 <[email protected]> Claude-Session: https://claude.ai/code/session_01Gth99spB1CzQmBFofXmU4Z
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
target/
|
||||||
@@ -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.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.5.16</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
<groupId>com.ankurm</groupId>
|
||||||
|
<artifactId>batch-legacy</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<properties><java.version>21</java.version></properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-batch</artifactId></dependency>
|
||||||
|
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency>
|
||||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
|
||||||
|
<dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-test</artifactId><scope>test</scope></dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
|
||||||
|
</project>
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<Integer> reader() {
|
||||||
|
return new ListItemReader<>(List.of(1, 2, 3, 4, 5, 6, 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ItemWriter<String> 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)
|
||||||
|
.<Integer, String>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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>4.1.1</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
<groupId>com.ankurm</groupId>
|
||||||
|
<artifactId>batch-migrated</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<properties><java.version>25</java.version></properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-batch-jdbc</artifactId></dependency>
|
||||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency>
|
||||||
|
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency>
|
||||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
|
||||||
|
<dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-test</artifactId><scope>test</scope></dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
|
||||||
|
</project>
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<Integer> reader() {
|
||||||
|
return new ListItemReader<>(List.of(1, 2, 3, 4, 5, 6, 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ItemWriter<String> writer() {
|
||||||
|
return chunk -> System.out.println("WRITE " + chunk.getItems());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ChunkListener<Integer, String> chunkListener() {
|
||||||
|
return new ChunkListener<>() {
|
||||||
|
@Override public void afterChunk(Chunk<String> chunk) {
|
||||||
|
System.out.println("CHUNK DONE, items in chunk=" + chunk.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Step squareStep(JobRepository repo, PlatformTransactionManager tx, ChunkListener<Integer, String> listener) {
|
||||||
|
return new StepBuilder("squareStep", repo)
|
||||||
|
.<Integer, String>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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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] <I,O>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.
|
||||||
|
|
||||||
@@ -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] <I,O>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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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 <I, O> core.step.builder.SimpleStepBuilder<I, O> chunk(int, PlatformTransactionManager);
|
||||||
|
public <I, O> core.step.builder.ChunkOrientedStepBuilder<I, O> chunk(int);
|
||||||
|
public <I, O> core.step.builder.SimpleStepBuilder<I, O> 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<I>);
|
||||||
|
public default void afterChunk(infrastructure.item.Chunk<O>);
|
||||||
|
public default void onChunkError(java.lang.Exception, infrastructure.item.Chunk<O>);
|
||||||
Executable
+69
@@ -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/<java.version>21/<java.version>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('<artifactId>spring-boot-starter-batch</artifactId></dependency>','<artifactId>spring-boot-starter-batch-jdbc</artifactId></dependency>\n <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency>')
|
||||||
|
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/\.<Integer, String>chunk(3, tx)/.<Integer, String>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
|
||||||
Reference in New Issue
Block a user