Skip to content

Commit d7e5bf7

Browse files
committed
FEATURE: validate step listeners
1 parent 10fd371 commit d7e5bf7

File tree

6 files changed

+124
-102
lines changed

6 files changed

+124
-102
lines changed

spring-batch-core/src/main/java/org/springframework/batch/core/listener/StepListenerFactoryBean.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package org.springframework.batch.core.listener;
1717

18+
import java.util.stream.Collectors;
19+
import java.util.stream.Stream;
20+
1821
import org.springframework.batch.core.StepListener;
1922

2023
/**
@@ -23,11 +26,22 @@
2326
*
2427
* @author Lucas Ward
2528
* @author Dan Garrette
29+
* @author Alexei KLENIN
2630
* @since 2.0
2731
* @see AbstractListenerFactoryBean
2832
* @see StepListenerMetaData
2933
*/
3034
public class StepListenerFactoryBean extends AbstractListenerFactoryBean<StepListener> {
35+
private static final String STR_STEP_LISTENER_ANNOTATIONS_LIST = Stream
36+
.of(StepListenerMetaData.values())
37+
.map(StepListenerMetaData::getAnnotation)
38+
.map(Class::getSimpleName)
39+
.map(annotation -> String.format("\t- @%s\n", annotation))
40+
.collect(Collectors.joining());
41+
private static final String ERR_OBJECT_NOT_STEP_LISTENER_TEMPLATE =
42+
"Object of type [%s] is not a valid step listener. " +
43+
"It must ether implement StepListener interface or have methods annotated with any of:\n" +
44+
STR_STEP_LISTENER_ANNOTATIONS_LIST;
3145

3246
@Override
3347
protected ListenerMetaData getMetaDataFromPropertyName(String propertyName) {
@@ -74,4 +88,19 @@ public static StepListener getListener(Object delegate) {
7488
public static boolean isListener(Object delegate) {
7589
return AbstractListenerFactoryBean.isListener(delegate, StepListener.class, StepListenerMetaData.values());
7690
}
91+
92+
/**
93+
* Asserts that {@code delegate} is a valid step listener. If this is not a case, throws an
94+
* {@link IllegalArgumentException} with message detailing the problem. Object is a valid
95+
* step listener is it ether implements interface {@link StepListener} or has any method
96+
* annotated with one of marker annotations.
97+
*
98+
* @param delegate the object to check
99+
*/
100+
public static void assertListener(Object delegate) {
101+
if (!isListener(delegate)) {
102+
throw new IllegalArgumentException(String.format(
103+
ERR_OBJECT_NOT_STEP_LISTENER_TEMPLATE, delegate.getClass().getName()));
104+
}
105+
}
77106
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.batch.core.ChunkListener;
2424
import org.springframework.batch.core.Step;
2525
import org.springframework.batch.core.StepExecutionListener;
26+
import org.springframework.batch.core.StepListener;
2627
import org.springframework.batch.core.annotation.AfterChunk;
2728
import org.springframework.batch.core.annotation.AfterChunkError;
2829
import org.springframework.batch.core.annotation.BeforeChunk;
@@ -47,6 +48,7 @@
4748
* @author Dave Syer
4849
* @author Michael Minella
4950
* @author Mahmoud Ben Hassine
51+
* @author Alexei Klenin
5052
*
5153
* @since 2.2
5254
*
@@ -159,10 +161,9 @@ public B listener(Object listener) {
159161
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterChunk.class));
160162
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterChunkError.class));
161163

162-
if(chunkListenerMethods.size() > 0) {
163-
StepListenerFactoryBean factory = new StepListenerFactoryBean();
164-
factory.setDelegate(listener);
165-
this.listener((ChunkListener) factory.getObject());
164+
if (!chunkListenerMethods.isEmpty()) {
165+
StepListener stepListener = StepListenerFactoryBean.getListener(listener);
166+
this.listener((ChunkListener) stepListener);
166167
}
167168

168169
@SuppressWarnings("unchecked")

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

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
* @author Chris Schaefer
9292
* @author Michael Minella
9393
* @author Mahmoud Ben Hassine
94+
* @author Alexei Klenin
9495
*
9596
* @since 2.2
9697
*/
@@ -204,18 +205,14 @@ public SimpleStepBuilder<I, O> listener(Object listener) {
204205
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInProcess.class));
205206
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInWrite.class));
206207

207-
if(skipListenerMethods.size() > 0) {
208-
StepListenerFactoryBean factory = new StepListenerFactoryBean();
209-
factory.setDelegate(listener);
210-
skipListeners.add((SkipListener) factory.getObject());
208+
if (!skipListenerMethods.isEmpty()) {
209+
StepListener stepListener = StepListenerFactoryBean.getListener(listener);
210+
skipListeners.add((SkipListener<I, O>) stepListener);
211211
}
212212

213-
@SuppressWarnings("unchecked")
214-
SimpleStepBuilder<I, O> result = this;
215-
return result;
213+
return this;
216214
}
217215

218-
219216
/**
220217
* Register a skip listener.
221218
*

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
*
6565
* @author Dave Syer
6666
* @author Mahmoud Ben Hassine
67+
* @author Alexei Klenin
6768
*
6869
* @since 2.2
6970
*/
@@ -265,7 +266,6 @@ public SimpleStepBuilder<I, O> readerIsTransactionalQueue() {
265266
* @param listener the object that has a method configured with listener annotation
266267
* @return this for fluent chaining
267268
*/
268-
@SuppressWarnings("unchecked")
269269
@Override
270270
public SimpleStepBuilder<I, O> listener(Object listener) {
271271
super.listener(listener);
@@ -281,18 +281,14 @@ public SimpleStepBuilder<I, O> listener(Object listener) {
281281
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnProcessError.class));
282282
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnWriteError.class));
283283

284-
if(itemListenerMethods.size() > 0) {
285-
StepListenerFactoryBean factory = new StepListenerFactoryBean();
286-
factory.setDelegate(listener);
287-
itemListeners.add((StepListener) factory.getObject());
284+
if (!itemListenerMethods.isEmpty()) {
285+
StepListener stepListener = StepListenerFactoryBean.getListener(listener);
286+
itemListeners.add(stepListener);
288287
}
289288

290-
@SuppressWarnings("unchecked")
291-
SimpleStepBuilder<I, O> result = this;
292-
return result;
289+
return this;
293290
}
294291

295-
296292
/**
297293
* Register an item reader listener.
298294
*

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818
import org.apache.commons.logging.Log;
1919
import org.apache.commons.logging.LogFactory;
20+
2021
import org.springframework.batch.core.Step;
2122
import org.springframework.batch.core.StepExecutionListener;
23+
import org.springframework.batch.core.StepListener;
2224
import org.springframework.batch.core.annotation.AfterStep;
2325
import org.springframework.batch.core.annotation.BeforeStep;
2426
import org.springframework.batch.core.listener.StepListenerFactoryBean;
@@ -40,6 +42,7 @@
4042
*
4143
* @author Dave Syer
4244
* @author Michael Minella
45+
* @author Alexei Klenin
4346
*
4447
* @since 2.2
4548
*/
@@ -91,14 +94,15 @@ public B startLimit(int startLimit) {
9194
* @return this for fluent chaining
9295
*/
9396
public B listener(Object listener) {
97+
StepListenerFactoryBean.assertListener(listener);
98+
9499
Set<Method> stepExecutionListenerMethods = new HashSet<>();
95100
stepExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeStep.class));
96101
stepExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterStep.class));
97102

98-
if(stepExecutionListenerMethods.size() > 0) {
99-
StepListenerFactoryBean factory = new StepListenerFactoryBean();
100-
factory.setDelegate(listener);
101-
properties.addStepExecutionListener((StepExecutionListener) factory.getObject());
103+
if (!stepExecutionListenerMethods.isEmpty()) {
104+
StepListener stepListener = StepListenerFactoryBean.getListener(listener);
105+
properties.addStepExecutionListener((StepExecutionListener) stepListener);
102106
}
103107

104108
@SuppressWarnings("unchecked")

0 commit comments

Comments
 (0)