Skip to content

Commit 873b742

Browse files
committed
Fix listener API allowing invalid listeners
Before listeners could be created without annotations which then would be ignored during runtime. Now Builders with listeners without annotations will throw a BuilderException containing the IllegalArgumentExceptions of the listeners. Resolves #4808 Signed-off-by: Sacha Leemann <[email protected]>
1 parent 639d64f commit 873b742

File tree

13 files changed

+118
-3
lines changed

13 files changed

+118
-3
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ public Job build() {
9393
job.setName(getName());
9494
job.setFlow(flow);
9595
super.enhance(job);
96+
if (!listenerErrors.isEmpty()) {
97+
throw new JobBuilderException(
98+
new IllegalArgumentException("Errors occurred while registering listeners" + listenerErrors));
99+
}
96100
try {
97101
job.afterPropertiesSet();
98102
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public abstract class JobBuilderHelper<B extends JobBuilderHelper<B>> {
5454

5555
private final CommonJobProperties properties;
5656

57+
protected List<Throwable> listenerErrors = new ArrayList<>();
58+
5759
/**
5860
* Create a new {@link JobBuilderHelper}.
5961
* @param jobRepository the job repository
@@ -83,6 +85,7 @@ public JobBuilderHelper(String name, JobRepository jobRepository) {
8385
*/
8486
protected JobBuilderHelper(JobBuilderHelper<?> parent) {
8587
this.properties = new CommonJobProperties(parent.properties);
88+
this.listenerErrors = parent.listenerErrors;
8689
}
8790

8891
/**
@@ -161,6 +164,10 @@ public B listener(Object listener) {
161164
factory.setDelegate(listener);
162165
properties.addJobExecutionListener((JobExecutionListener) factory.getObject());
163166
}
167+
else {
168+
listenerErrors
169+
.add(new IllegalArgumentException("Missing @BeforeJob or @AfterJob annotations on Listener."));
170+
}
164171

165172
@SuppressWarnings("unchecked")
166173
B result = (B) this;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ public Job build() {
5353
SimpleJob job = new SimpleJob(getName());
5454
super.enhance(job);
5555
job.setSteps(steps);
56+
if (!listenerErrors.isEmpty()) {
57+
throw new JobBuilderException(
58+
new IllegalArgumentException("Errors occurred while registering listeners" + listenerErrors));
59+
}
5660
try {
5761
job.afterPropertiesSet();
5862
}

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ public TaskletStep build() {
107107

108108
step.setChunkListeners(chunkListeners.toArray(new ChunkListener[0]));
109109

110+
if (!listenerErrors.isEmpty()) {
111+
throw new StepBuilderException(
112+
new IllegalArgumentException("Errors occurred while registering listeners" + listenerErrors));
113+
}
114+
110115
if (this.transactionManager != null) {
111116
step.setTransactionManager(this.transactionManager);
112117
}
@@ -170,17 +175,21 @@ public B listener(ChunkListener listener) {
170175
@Override
171176
public B listener(Object listener) {
172177
super.listener(listener);
173-
174178
Set<Method> chunkListenerMethods = new HashSet<>();
175179
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeChunk.class));
176180
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterChunk.class));
177181
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterChunkError.class));
178182

179183
if (!chunkListenerMethods.isEmpty()) {
184+
listenerErrors.clear();
180185
StepListenerFactoryBean factory = new StepListenerFactoryBean();
181186
factory.setDelegate(listener);
182187
this.listener((ChunkListener) factory.getObject());
183188
}
189+
else if (!listenerErrors.isEmpty()) {
190+
listenerErrors.add(new IllegalArgumentException(
191+
"Missing @BeforeChunk, @AfterChunk or @AfterChunkError annotations on Listener."));
192+
}
184193

185194
return self();
186195
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,21 @@ protected Tasklet createTasklet() {
194194
@Override
195195
public FaultTolerantStepBuilder<I, O> listener(Object listener) {
196196
super.listener(listener);
197-
198197
Set<Method> skipListenerMethods = new HashSet<>();
199198
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInRead.class));
200199
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInProcess.class));
201200
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInWrite.class));
202201

203202
if (!skipListenerMethods.isEmpty()) {
203+
listenerErrors.clear();
204204
StepListenerFactoryBean factory = new StepListenerFactoryBean();
205205
factory.setDelegate(listener);
206206
skipListeners.add((SkipListener<I, O>) factory.getObject());
207207
}
208+
else if (!listenerErrors.isEmpty()) {
209+
listenerErrors.add(new IllegalArgumentException(
210+
"Missing @OnSkipInRead, @OnSkipInProcess or @OnSkipInWrite annotations on Listener."));
211+
}
208212

209213
return this;
210214
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ public Step build() {
6060
step.setName(getName());
6161
step.setFlow(flow);
6262
super.enhance(step);
63+
if (!listenerErrors.isEmpty()) {
64+
throw new StepBuilderException(
65+
new IllegalArgumentException("Errors occurred while registering listeners" + listenerErrors));
66+
}
6367
try {
6468
step.afterPropertiesSet();
6569
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ public Step build() {
8686
JobStep step = new JobStep();
8787
step.setName(getName());
8888
super.enhance(step);
89+
if (!listenerErrors.isEmpty()) {
90+
throw new StepBuilderException(
91+
new IllegalArgumentException("Errors occurred while registering listeners" + listenerErrors));
92+
}
8993
if (job != null) {
9094
step.setJob(job);
9195
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ public Step build() {
163163
step.setName(getName());
164164
super.enhance(step);
165165

166+
if (!listenerErrors.isEmpty()) {
167+
throw new StepBuilderException(
168+
new IllegalArgumentException("Errors occurred while registering listeners" + listenerErrors));
169+
}
170+
166171
if (partitionHandler != null) {
167172
step.setPartitionHandler(partitionHandler);
168173
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,15 @@ public SimpleStepBuilder<I, O> listener(Object listener) {
270270
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnWriteError.class));
271271

272272
if (!itemListenerMethods.isEmpty()) {
273+
listenerErrors.clear();
273274
StepListenerFactoryBean factory = new StepListenerFactoryBean();
274275
factory.setDelegate(listener);
275276
itemListeners.add((StepListener) factory.getObject());
276277
}
278+
else if (!listenerErrors.isEmpty()) {
279+
listenerErrors.add(new IllegalArgumentException(
280+
"Missing @BeforeRead, @AfterRead, @BeforeProcess, @AfterProcess, @BeforeWrite, @AfterWrite, @OnReadError, @OnProcessError or @OnWriteError annotations on Listener."));
281+
}
277282

278283
return this;
279284
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public abstract class StepBuilderHelper<B extends StepBuilderHelper<B>> {
5353

5454
protected final CommonStepProperties properties;
5555

56+
protected List<Throwable> listenerErrors = new ArrayList<>();
57+
5658
/**
5759
* Create a new {@link StepBuilderHelper} with the given job repository.
5860
* @param jobRepository the job repository
@@ -82,6 +84,7 @@ public StepBuilderHelper(String name, JobRepository jobRepository) {
8284
*/
8385
protected StepBuilderHelper(StepBuilderHelper<?> parent) {
8486
this.properties = new CommonStepProperties(parent.properties);
87+
this.listenerErrors = parent.listenerErrors;
8588
}
8689

8790
/**
@@ -125,6 +128,10 @@ public B listener(Object listener) {
125128
factory.setDelegate(listener);
126129
properties.addStepExecutionListener((StepExecutionListener) factory.getObject());
127130
}
131+
else {
132+
listenerErrors
133+
.add(new IllegalArgumentException("Missing @BeforeStep or @AfterStep annotations on Listener."));
134+
}
128135

129136
return self();
130137
}

0 commit comments

Comments
 (0)