Skip to content

Commit f39f070

Browse files
committed
Improve Step/Job builder APIs to guide users to set mandatory properties
Before this commit, the user had to manually set the job repository and transaction manager on `JobBuilder` and `StepBuilder` instances with a chained call to `.repository(jobRepository)` and `.transactionManager(transactionManager)`. This is error prone and can lead to runtime errors if these properties are not set. This commit introduces new APIs to guide the user to set these properties at builder creation time. Resolves #4192
1 parent d11b5b2 commit f39f070

File tree

63 files changed

+520
-302
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+520
-302
lines changed

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/JobBuilderFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public JobBuilderFactory(JobRepository jobRepository) {
5151
* @return a job builder
5252
*/
5353
public JobBuilder get(String name) {
54-
return new JobBuilder(name).repository(this.jobRepository);
54+
return new JobBuilder(name, this.jobRepository);
5555
}
5656

5757
}

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/StepBuilderFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public StepBuilderFactory(JobRepository jobRepository) {
5353
* @return a step builder
5454
*/
5555
public StepBuilder get(String name) {
56-
return new StepBuilder(name).repository(this.jobRepository);
56+
return new StepBuilder(name, this.jobRepository);
5757
}
5858

5959
}

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/StepParserStepFactoryBean.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,6 @@ protected void enhanceCommonStep(StepBuilderHelper<?> builder) {
274274
if (startLimit != null) {
275275
builder.startLimit(startLimit);
276276
}
277-
builder.repository(jobRepository);
278277
for (Object listener : stepExecutionListeners) {
279278
if (listener instanceof StepExecutionListener) {
280279
builder.listener((StepExecutionListener) listener);
@@ -290,10 +289,11 @@ protected Step createPartitionStep() {
290289

291290
PartitionStepBuilder builder;
292291
if (partitioner != null) {
293-
builder = new StepBuilder(name).partitioner(step != null ? step.getName() : name, partitioner).step(step);
292+
builder = new StepBuilder(name, jobRepository)
293+
.partitioner(step != null ? step.getName() : name, partitioner).step(step);
294294
}
295295
else {
296-
builder = new StepBuilder(name).partitioner(step);
296+
builder = new StepBuilder(name, jobRepository).partitioner(step);
297297
}
298298
enhanceCommonStep(builder);
299299

@@ -401,7 +401,7 @@ else if (skipLimit != null) {
401401
* @return the {@link FaultTolerantStepBuilder}.
402402
*/
403403
protected FaultTolerantStepBuilder<I, O> getFaultTolerantStepBuilder(String stepName) {
404-
return new FaultTolerantStepBuilder<>(new StepBuilder(stepName));
404+
return new FaultTolerantStepBuilder<>(new StepBuilder(stepName, jobRepository));
405405
}
406406

407407
protected void registerItemListeners(SimpleStepBuilder<I, O> builder) {
@@ -445,16 +445,16 @@ protected CompletionPolicy getCompletionPolicy() {
445445
}
446446

447447
protected SimpleStepBuilder<I, O> getSimpleStepBuilder(String stepName) {
448-
return new SimpleStepBuilder<>(new StepBuilder(stepName));
448+
return new SimpleStepBuilder<>(new StepBuilder(stepName, jobRepository));
449449
}
450450

451451
/**
452452
* Create a new {@link TaskletStep}.
453453
* @return a new {@link TaskletStep}
454454
*/
455455
protected TaskletStep createTaskletStep() {
456-
TaskletStepBuilder builder = new TaskletStepBuilder(new StepBuilder(name))
457-
.transactionManager(transactionManager).tasklet(tasklet);
456+
TaskletStepBuilder builder = new TaskletStepBuilder(new StepBuilder(name, jobRepository)).tasklet(tasklet,
457+
transactionManager);
458458
enhanceTaskletStepBuilder(builder);
459459
return builder.build();
460460
}
@@ -512,14 +512,14 @@ public boolean rollbackOn(Throwable ex) {
512512
* @return the {@link org.springframework.batch.core.job.flow.FlowStep}.
513513
*/
514514
protected Step createFlowStep() {
515-
FlowStepBuilder builder = new StepBuilder(name).flow(flow);
515+
FlowStepBuilder builder = new StepBuilder(name, jobRepository).flow(flow);
516516
enhanceCommonStep(builder);
517517
return builder.build();
518518
}
519519

520520
private Step createJobStep() throws Exception {
521521

522-
JobStepBuilder builder = new StepBuilder(name).job(job);
522+
JobStepBuilder builder = new StepBuilder(name, jobRepository).job(job);
523523
enhanceCommonStep(builder);
524524
builder.parametersExtractor(jobParametersExtractor);
525525
builder.launcher(jobLauncher);

spring-batch-core/src/main/java/org/springframework/batch/core/job/builder/JobBuilder.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2013 the original author or authors.
2+
* Copyright 2006-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,11 +17,13 @@
1717

1818
import org.springframework.batch.core.Step;
1919
import org.springframework.batch.core.job.flow.Flow;
20+
import org.springframework.batch.core.repository.JobRepository;
2021

2122
/**
2223
* Convenience for building jobs of various kinds.
2324
*
2425
* @author Dave Syer
26+
* @author Mahmoud Ben Hassine
2527
* @since 2.2
2628
*
2729
*/
@@ -30,11 +32,24 @@ public class JobBuilder extends JobBuilderHelper<JobBuilder> {
3032
/**
3133
* Create a new builder for a job with the given name.
3234
* @param name the name of the job
35+
* @deprecated use {@link JobBuilder#JobBuilder(String, JobRepository)}
3336
*/
37+
@Deprecated(since = "5.0")
3438
public JobBuilder(String name) {
3539
super(name);
3640
}
3741

42+
/**
43+
* Create a new builder for a job with the given name.
44+
* @param name the name of the job
45+
* @param jobRepository the job repository to which the job should report to
46+
* @since 5.0
47+
*/
48+
public JobBuilder(String name, JobRepository jobRepository) {
49+
super(name);
50+
super.repository(jobRepository);
51+
}
52+
3853
/**
3954
* Create a new job builder that will execute a step or sequence of steps.
4055
* @param step a step to execute

spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/StepBuilder.java

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,64 @@
1919
import org.springframework.batch.core.Step;
2020
import org.springframework.batch.core.job.flow.Flow;
2121
import org.springframework.batch.core.partition.support.Partitioner;
22+
import org.springframework.batch.core.repository.JobRepository;
2223
import org.springframework.batch.core.step.tasklet.Tasklet;
2324
import org.springframework.batch.repeat.CompletionPolicy;
25+
import org.springframework.transaction.PlatformTransactionManager;
2426

2527
/**
2628
* Convenient entry point for building all kinds of steps. Use this as a factory for
2729
* fluent builders of any step.
2830
*
2931
* @author Dave Syer
32+
* @author Mahmoud Ben Hassine
3033
* @since 2.2
3134
*/
3235
public class StepBuilder extends StepBuilderHelper<StepBuilder> {
3336

3437
/**
3538
* Initialize a step builder for a step with the given name.
3639
* @param name the name of the step
40+
* @deprecated use {@link StepBuilder#StepBuilder(String, JobRepository)}
3741
*/
42+
@Deprecated(since = "5.0")
3843
public StepBuilder(String name) {
3944
super(name);
4045
}
4146

47+
/**
48+
* Initialize a step builder for a step with the given name and job repository.
49+
* @param name the name of the step
50+
* @param jobRepository the job repository to which the step should report to.
51+
* @since 5.0
52+
*/
53+
public StepBuilder(String name, JobRepository jobRepository) {
54+
super(name);
55+
super.repository(jobRepository);
56+
}
57+
4258
/**
4359
* Build a step with a custom tasklet, not necessarily item processing.
4460
* @param tasklet a tasklet
4561
* @return a {@link TaskletStepBuilder}
62+
* @deprecated use {@link StepBuilder#tasklet(Tasklet, PlatformTransactionManager)}
4663
*/
64+
@Deprecated(since = "5.0")
4765
public TaskletStepBuilder tasklet(Tasklet tasklet) {
4866
return new TaskletStepBuilder(this).tasklet(tasklet);
4967
}
5068

69+
/**
70+
* Build a step with a custom tasklet, not necessarily item processing.
71+
* @param tasklet a tasklet
72+
* @param transactionManager the transaction manager to use for the tasklet
73+
* @return a {@link TaskletStepBuilder}
74+
* @since 5.0
75+
*/
76+
public TaskletStepBuilder tasklet(Tasklet tasklet, PlatformTransactionManager transactionManager) {
77+
return new TaskletStepBuilder(this).tasklet(tasklet, transactionManager);
78+
}
79+
5180
/**
5281
* Build a step that processes items in chunks with the size provided. To extend the
5382
* step to being fault tolerant, call the {@link SimpleStepBuilder#faultTolerant()}
@@ -62,11 +91,35 @@ public TaskletStepBuilder tasklet(Tasklet tasklet) {
6291
* @return a {@link SimpleStepBuilder}
6392
* @param <I> the type of item to be processed as input
6493
* @param <O> the type of item to be output
94+
* @deprecated use {@link StepBuilder#chunk(int, PlatformTransactionManager)}
6595
*/
96+
@Deprecated(since = "5.0")
6697
public <I, O> SimpleStepBuilder<I, O> chunk(int chunkSize) {
6798
return new SimpleStepBuilder<I, O>(this).chunk(chunkSize);
6899
}
69100

101+
/**
102+
* Build a step that processes items in chunks with the size provided. To extend the
103+
* step to being fault tolerant, call the {@link SimpleStepBuilder#faultTolerant()}
104+
* method on the builder. In most cases you will want to parameterize your call to
105+
* this method, to preserve the type safety of your readers and writers, e.g.
106+
*
107+
* <pre>
108+
* new StepBuilder(&quot;step1&quot;).&lt;Order, Ledger&gt; chunk(100, transactionManager).reader(new OrderReader()).writer(new LedgerWriter())
109+
* // ... etc.
110+
* </pre>
111+
* @param chunkSize the chunk size (commit interval)
112+
* @param transactionManager the transaction manager to use for the chunk-oriented
113+
* tasklet
114+
* @return a {@link SimpleStepBuilder}
115+
* @param <I> the type of item to be processed as input
116+
* @param <O> the type of item to be output
117+
* @since 5.0
118+
*/
119+
public <I, O> SimpleStepBuilder<I, O> chunk(int chunkSize, PlatformTransactionManager transactionManager) {
120+
return new SimpleStepBuilder<I, O>(this).transactionManager(transactionManager).chunk(chunkSize);
121+
}
122+
70123
/**
71124
* Build a step that processes items in chunks with the completion policy provided. To
72125
* extend the step to being fault tolerant, call the
@@ -81,12 +134,39 @@ public <I, O> SimpleStepBuilder<I, O> chunk(int chunkSize) {
81134
* @param completionPolicy the completion policy to use to control chunk processing
82135
* @return a {@link SimpleStepBuilder}
83136
* @param <I> the type of item to be processed as input
84-
* @param <O> the type of item to be output *
137+
* @param <O> the type of item to be output
138+
* @deprecated use
139+
* {@link StepBuilder#chunk(CompletionPolicy, PlatformTransactionManager)}
85140
*/
141+
@Deprecated(since = "5.0")
86142
public <I, O> SimpleStepBuilder<I, O> chunk(CompletionPolicy completionPolicy) {
87143
return new SimpleStepBuilder<I, O>(this).chunk(completionPolicy);
88144
}
89145

146+
/**
147+
* Build a step that processes items in chunks with the completion policy provided. To
148+
* extend the step to being fault tolerant, call the
149+
* {@link SimpleStepBuilder#faultTolerant()} method on the builder. In most cases you
150+
* will want to parameterize your call to this method, to preserve the type safety of
151+
* your readers and writers, e.g.
152+
*
153+
* <pre>
154+
* new StepBuilder(&quot;step1&quot;).&lt;Order, Ledger&gt; chunk(100, transactionManager).reader(new OrderReader()).writer(new LedgerWriter())
155+
* // ... etc.
156+
* </pre>
157+
* @param completionPolicy the completion policy to use to control chunk processing
158+
* @param transactionManager the transaction manager to use for the chunk-oriented
159+
* tasklet
160+
* @return a {@link SimpleStepBuilder}
161+
* @param <I> the type of item to be processed as input
162+
* @param <O> the type of item to be output
163+
* @since 5.0
164+
*/
165+
public <I, O> SimpleStepBuilder<I, O> chunk(CompletionPolicy completionPolicy,
166+
PlatformTransactionManager transactionManager) {
167+
return new SimpleStepBuilder<I, O>(this).transactionManager(transactionManager).chunk(completionPolicy);
168+
}
169+
90170
/**
91171
* Create a partition step builder for a remote (or local) step.
92172
* @param stepName the name of the remote or delegate step

spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/TaskletStepBuilder.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
package org.springframework.batch.core.step.builder;
1717

1818
import org.springframework.batch.core.step.tasklet.Tasklet;
19+
import org.springframework.transaction.PlatformTransactionManager;
1920

2021
/**
2122
* Builder for tasklet step based on a custom tasklet (not item oriented).
2223
*
2324
* @author Dave Syer
25+
* @author Mahmoud Ben Hassine
2426
* @since 2.2
2527
*/
2628
public class TaskletStepBuilder extends AbstractTaskletStepBuilder<TaskletStepBuilder> {
@@ -39,12 +41,26 @@ public TaskletStepBuilder(StepBuilderHelper<?> parent) {
3941
/**
4042
* @param tasklet the tasklet to use
4143
* @return this for fluent chaining
44+
* @deprecated use
45+
* {@link TaskletStepBuilder#tasklet(Tasklet, PlatformTransactionManager)}
4246
*/
47+
@Deprecated(since = "5.0")
4348
public TaskletStepBuilder tasklet(Tasklet tasklet) {
4449
this.tasklet = tasklet;
4550
return this;
4651
}
4752

53+
/**
54+
* @param tasklet the tasklet to use
55+
* @return this for fluent chaining
56+
* @since 5.0
57+
*/
58+
public TaskletStepBuilder tasklet(Tasklet tasklet, PlatformTransactionManager transactionManager) {
59+
this.tasklet = tasklet;
60+
super.transactionManager(transactionManager);
61+
return this;
62+
}
63+
4864
@Override
4965
protected TaskletStepBuilder self() {
5066
return this;

spring-batch-core/src/main/java/org/springframework/batch/core/step/factory/FaultTolerantStepFactoryBean.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2013 the original author or authors.
2+
* Copyright 2006-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -214,7 +214,7 @@ public void setProcessorTransactional(boolean processorTransactional) {
214214

215215
@Override
216216
protected SimpleStepBuilder<T, S> createBuilder(String name) {
217-
return new FaultTolerantStepBuilder<>(new StepBuilder(name));
217+
return new FaultTolerantStepBuilder<>(new StepBuilder(name, jobRepository));
218218
}
219219

220220
@Override

spring-batch-core/src/main/java/org/springframework/batch/core/step/factory/SimpleStepFactoryBean.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2013 the original author or authors.
2+
* Copyright 2006-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -57,6 +57,7 @@
5757
* @see FaultTolerantStepFactoryBean
5858
* @author Dave Syer
5959
* @author Robert Kasanicky
60+
* @author Mahmoud Ben Hassine
6061
*
6162
*/
6263
public class SimpleStepFactoryBean<T, S> implements FactoryBean<Step>, BeanNameAware {
@@ -81,7 +82,7 @@ public class SimpleStepFactoryBean<T, S> implements FactoryBean<Step>, BeanNameA
8182

8283
private int transactionTimeout = DefaultTransactionAttribute.TIMEOUT_DEFAULT;
8384

84-
private JobRepository jobRepository;
85+
protected JobRepository jobRepository;
8586

8687
private boolean singleton = true;
8788

@@ -318,7 +319,7 @@ public final Step getObject() throws Exception {
318319
}
319320

320321
protected SimpleStepBuilder<T, S> createBuilder(String name) {
321-
return new SimpleStepBuilder<>(new StepBuilder(name));
322+
return new SimpleStepBuilder<>(new StepBuilder(name, jobRepository));
322323
}
323324

324325
@Override

0 commit comments

Comments
 (0)