Skip to content

Commit 5e48bc0

Browse files
committed
Fix key collision in execution context with item streams
Credits to @jpraet ! Change set taken from #292
1 parent c770192 commit 5e48bc0

28 files changed

+141
-66
lines changed

spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkMonitor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2024 the original author or authors.
2+
* Copyright 2006-2025 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.
@@ -35,6 +35,7 @@
3535
* @author Dave Syer
3636
* @author Mahmoud Ben Hassine
3737
* @author Seungrae Kim
38+
* @author Jimmy Praet
3839
* @since 2.0
3940
* @deprecated Since 6.0 with no replacement. Scheduled for removal in 7.0.
4041
*/
@@ -68,7 +69,6 @@ public ChunkMonitorData(int offset, int chunkSize) {
6869
private ItemReader<?> reader;
6970

7071
public ChunkMonitor() {
71-
this.setExecutionContextName(ChunkMonitor.class.getName());
7272
}
7373

7474
/**

spring-batch-core/src/test/java/org/springframework/batch/core/partition/ExampleItemReader.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2008-2023 the original author or authors.
2+
* Copyright 2008-2025 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.
@@ -23,7 +23,6 @@
2323
import org.springframework.batch.infrastructure.item.ItemStreamException;
2424
import org.springframework.batch.infrastructure.item.ItemStreamReader;
2525
import org.springframework.batch.infrastructure.item.support.AbstractItemStreamItemReader;
26-
import org.springframework.util.ClassUtils;
2726

2827
/**
2928
* {@link ItemStreamReader} with hard-coded input data.
@@ -43,7 +42,6 @@ public class ExampleItemReader extends AbstractItemStreamItemReader<String> {
4342
public static volatile boolean fail = false;
4443

4544
public ExampleItemReader() {
46-
this.setExecutionContextName(ClassUtils.getShortName(this.getClass()));
4745
}
4846

4947
/**

spring-batch-core/src/test/java/org/springframework/batch/core/step/item/ChunkMonitorTests.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2023 the original author or authors.
2+
* Copyright 2006-2025 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.
@@ -32,7 +32,7 @@
3232
/**
3333
* @author Dave Syer
3434
* @author Mahmoud Ben Hassine
35-
*
35+
* @author Jimmy Praet
3636
*/
3737
class ChunkMonitorTests {
3838

@@ -96,7 +96,7 @@ void testClose() {
9696
@Test
9797
void testOpen() {
9898
ExecutionContext executionContext = new ExecutionContext();
99-
executionContext.putInt(ChunkMonitor.class.getName() + ".OFFSET", 2);
99+
executionContext.putInt(monitor.getExecutionContextKey("OFFSET"), 2);
100100
monitor.open(executionContext);
101101
assertEquals(2, count);
102102
assertEquals(0, monitor.getOffset());
@@ -120,7 +120,7 @@ void testOpenWithErrorInReader() {
120120
}
121121
});
122122
ExecutionContext executionContext = new ExecutionContext();
123-
executionContext.putInt(ChunkMonitor.class.getName() + ".OFFSET", 2);
123+
executionContext.putInt(monitor.getExecutionContextKey("OFFSET"), 2);
124124
assertThrows(ItemStreamException.class, () -> monitor.open(executionContext));
125125
}
126126

@@ -131,7 +131,7 @@ void testUpdateOnBoundary() {
131131
monitor.update(executionContext);
132132
assertEquals(0, executionContext.size());
133133

134-
executionContext.put(ChunkMonitor.class.getName() + ".OFFSET", 3);
134+
executionContext.put(monitor.getExecutionContextKey("OFFSET"), 3);
135135
monitor.update(executionContext);
136136
assertEquals(0, executionContext.size());
137137
}

spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/ItemStreamSupport.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2024 the original author or authors.
2+
* Copyright 2006-2025 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,6 +17,8 @@
1717

1818
import org.jspecify.annotations.Nullable;
1919
import org.springframework.batch.infrastructure.item.util.ExecutionContextUserSupport;
20+
import org.springframework.beans.factory.BeanNameAware;
21+
import org.springframework.util.ClassUtils;
2022

2123
/**
2224
* Empty method implementation of {@link ItemStream}.
@@ -25,12 +27,21 @@
2527
* @author Dean de Bree
2628
* @author Mahmoud Ben Hassine
2729
* @author Stefano Cordio
30+
* @author Jimmy Praet
2831
*
2932
*/
30-
public abstract class ItemStreamSupport implements ItemStream {
33+
public abstract class ItemStreamSupport implements ItemStream, BeanNameAware {
3134

3235
private final ExecutionContextUserSupport executionContextUserSupport = new ExecutionContextUserSupport();
3336

37+
private final String defaultName = ClassUtils.getShortName(getClass());
38+
39+
private @Nullable String name;
40+
41+
public ItemStreamSupport() {
42+
setName(defaultName);
43+
}
44+
3445
/**
3546
* The name of the component which will be used as a stem for keys in the
3647
* {@link ExecutionContext}. Subclasses should provide a default value, e.g. the short
@@ -41,6 +52,20 @@ public void setName(String name) {
4152
this.setExecutionContextName(name);
4253
}
4354

55+
/**
56+
* Set the name of the bean in the bean factory that created this bean. The bean name
57+
* will only be used as name of the component in case it hasn't already been
58+
* explicitly set to a value other than the default. {@link #setName(String)}
59+
* @see BeanNameAware#setBeanName(String)
60+
* @since 6.0
61+
*/
62+
@Override
63+
public void setBeanName(String name) {
64+
if (defaultName.equals(this.name)) {
65+
setName(name);
66+
}
67+
}
68+
4469
/**
4570
* Get the name of the component
4671
* @return the name of the component
@@ -50,6 +75,7 @@ public void setName(String name) {
5075
}
5176

5277
protected void setExecutionContextName(String name) {
78+
this.name = name;
5379
executionContextUserSupport.setName(name);
5480
}
5581

spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/avro/AvroItemReader.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2023 the original author or authors.
2+
* Copyright 2019-2025 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.
@@ -35,7 +35,6 @@
3535
import org.springframework.batch.infrastructure.item.support.AbstractItemCountingItemStreamItemReader;
3636
import org.springframework.core.io.Resource;
3737
import org.springframework.util.Assert;
38-
import org.springframework.util.ClassUtils;
3938

4039
/**
4140
* An {@link ItemReader} that deserializes data from a {@link Resource} containing
@@ -48,6 +47,7 @@
4847
* @author David Turanski
4948
* @author Mahmoud Ben Hassine
5049
* @author Song JaeGeun
50+
* @author Jimmy Praet
5151
* @since 4.2
5252
*/
5353
public class AvroItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> {
@@ -67,8 +67,6 @@ public class AvroItemReader<T> extends AbstractItemCountingItemStreamItemReader<
6767
* @param clazz the data type to be deserialized.
6868
*/
6969
public AvroItemReader(Resource resource, Class<T> clazz) {
70-
setName(ClassUtils.getShortName(AvroItemReader.class));
71-
7270
Assert.notNull(resource, "'resource' is required.");
7371
Assert.notNull(clazz, "'class' is required.");
7472

@@ -86,8 +84,6 @@ public AvroItemReader(Resource resource, Class<T> clazz) {
8684
* @param schema the {@link Resource} containing the Avro schema.
8785
*/
8886
public AvroItemReader(Resource data, Resource schema) {
89-
setName(ClassUtils.getShortName(AvroItemReader.class));
90-
9187
Assert.notNull(data, "'data' is required.");
9288
Assert.state(data.exists(), "'data' " + data.getFilename() + " does not exist.");
9389
Assert.notNull(schema, "'schema' is required");

spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/data/MongoCursorItemReader.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@
3737
import org.springframework.data.mongodb.util.json.ParameterBindingJsonReader;
3838
import org.springframework.data.util.CloseableIterator;
3939
import org.springframework.util.Assert;
40-
import org.springframework.util.ClassUtils;
4140
import org.springframework.util.StringUtils;
4241

4342
/**
4443
* Cursor-based {@link ItemReader} implementation for MongoDB.
4544
*
4645
* @author LEE Juchan
4746
* @author Mahmoud Ben Hassine
47+
* @author Jimmy Praet
4848
* @since 5.1
4949
*/
5050
public class MongoCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> implements InitializingBean {
@@ -86,7 +86,6 @@ public MongoCursorItemReader(MongoOperations template, Class<? extends T> target
8686
Assert.notNull(targetType, "Target type must not be null");
8787
this.template = template;
8888
this.targetType = targetType;
89-
setName(ClassUtils.getShortName(MongoCursorItemReader.class));
9089
}
9190

9291
/**

spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/data/MongoPagingItemReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
* @author Takaaki Iida
7979
* @author Mahmoud Ben Hassine
8080
* @author Parikshit Dutta
81+
* @author Jimmy Praet
8182
*/
8283
public class MongoPagingItemReader<T> extends AbstractPaginatedDataItemReader<T> implements InitializingBean {
8384

@@ -110,7 +111,6 @@ public MongoPagingItemReader(MongoOperations template, Class<? extends T> type)
110111
Assert.notNull(type, "Target type must not be null");
111112
this.template = template;
112113
this.type = type;
113-
setName(ClassUtils.getShortName(MongoPagingItemReader.class));
114114
}
115115

116116
/**

spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/data/RepositoryItemReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
* @author Michael Minella
8080
* @author Antoine Kapps
8181
* @author Mahmoud Ben Hassine
82+
* @author Jimmy Praet
8283
* @since 2.2
8384
*/
8485
public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> implements InitializingBean {
@@ -114,7 +115,6 @@ public RepositoryItemReader(PagingAndSortingRepository<?, ?> repository, Map<Str
114115
Assert.notNull(sorts, "A Map of sorts is required.");
115116
this.repository = repository;
116117
this.sorts = sorts;
117-
setName(ClassUtils.getShortName(RepositoryItemReader.class));
118118
}
119119

120120
/**

spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/database/AbstractPagingItemReader.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2023 the original author or authors.
2+
* Copyright 2006-2025 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.
@@ -27,7 +27,6 @@
2727
import org.springframework.batch.infrastructure.item.support.AbstractItemCountingItemStreamItemReader;
2828
import org.springframework.beans.factory.InitializingBean;
2929
import org.springframework.util.Assert;
30-
import org.springframework.util.ClassUtils;
3130

3231
/**
3332
* Abstract {@link ItemStreamReader} for to extend when reading database records in a
@@ -46,6 +45,7 @@
4645
* @author Dave Syer
4746
* @author Mahmoud Ben Hassine
4847
* @author Stefano Cordio
48+
* @author Jimmy Praet
4949
* @since 2.0
5050
*/
5151
public abstract class AbstractPagingItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
@@ -66,7 +66,6 @@ public abstract class AbstractPagingItemReader<T> extends AbstractItemCountingIt
6666
private final Lock lock = new ReentrantLock();
6767

6868
public AbstractPagingItemReader() {
69-
setName(ClassUtils.getShortName(AbstractPagingItemReader.class));
7069
}
7170

7271
/**

spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/database/JdbcCursorItemReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
* @author Thomas Risberg
6262
* @author Mahmoud Ben Hassine
6363
* @author Stefano Cordio
64+
* @author Jimmy Praet
6465
*/
6566
public class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {
6667

@@ -83,7 +84,6 @@ public JdbcCursorItemReader(DataSource dataSource, String sql, RowMapper<T> rowM
8384
Assert.notNull(rowMapper, "RowMapper must not be null");
8485
this.sql = sql;
8586
this.rowMapper = rowMapper;
86-
setName(ClassUtils.getShortName(JdbcCursorItemReader.class));
8787
}
8888

8989
/**

0 commit comments

Comments
 (0)