From 551bde9512445a72baa7732fa9bc6bb458e2b407 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Mon, 11 May 2026 10:21:46 +0800 Subject: [PATCH] RecordFieldSetMapper shouldn't reject null values Close GH-5392 Signed-off-by: Yanming Zhou --- .../file/mapping/RecordFieldSetMapper.java | 5 ++--- .../mapping/RecordFieldSetMapperTests.java | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/file/mapping/RecordFieldSetMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/file/mapping/RecordFieldSetMapper.java index 13227ec96e..5bccf26adc 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/file/mapping/RecordFieldSetMapper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/file/mapping/RecordFieldSetMapper.java @@ -33,6 +33,7 @@ * @param type of mapped items * @author Mahmoud Ben Hassine * @author Seungyong Hong + * @author Yanming Zhou * @since 4.3 */ public class RecordFieldSetMapper implements FieldSetMapper { @@ -76,14 +77,12 @@ public T mapFieldSet(FieldSet fieldSet) { Assert.isTrue(fieldSet.getFieldCount() == this.constructorParameterNames.length, "Fields count must be equal to record components count"); Assert.isTrue(fieldSet.hasNames(), "Field names must be specified"); - Object[] args = new Object[this.constructorParameterNames.length]; + @Nullable Object[] args = new Object[this.constructorParameterNames.length]; for (int i = 0; i < args.length; i++) { String name = this.constructorParameterNames[i]; Class type = this.constructorParameterTypes[i]; Assert.notNull(name, "Constructor parameter names must not be null"); Object converted = this.typeConverter.convertIfNecessary(fieldSet.readRawString(name), type); - Assert.notNull(converted, - () -> String.format("Cannot convert field '%s' to required type '%s'", name, type.getName())); args[i] = converted; } return BeanUtils.instantiateClass(this.mappedConstructor, args); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/infrastructure/item/file/mapping/RecordFieldSetMapperTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/infrastructure/item/file/mapping/RecordFieldSetMapperTests.java index 081a7abb32..41d815563b 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/infrastructure/item/file/mapping/RecordFieldSetMapperTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/infrastructure/item/file/mapping/RecordFieldSetMapperTests.java @@ -17,17 +17,18 @@ import org.junit.jupiter.api.Test; -import org.springframework.batch.infrastructure.item.file.mapping.RecordFieldSetMapper; import org.springframework.batch.infrastructure.item.file.transform.DefaultFieldSet; import org.springframework.batch.infrastructure.item.file.transform.FieldSet; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; /** * @author Mahmoud Ben Hassine * @author Seungyong Hong + * @author Yanming Zhou */ class RecordFieldSetMapperTests { @@ -83,10 +84,25 @@ void testMapFieldSetWhenEmptyRecord() { assertNotNull(empty); } + @Test + void testMapFieldSetWhenFieldsMayBeNull() { + // given + RecordFieldSetMapper recordFieldSetMapper = new RecordFieldSetMapper<>(User.class); + FieldSet fieldSet = new DefaultFieldSet(new String[] { "", "foo" }, new String[] { "id", "name" }); + + // when + User user = recordFieldSetMapper.mapFieldSet(fieldSet); + assertNotNull(user); + assertNull(user.id()); + } + record Person(int id, String name) { } record EmptyRecord() { } + record User(Integer id, String name) { + } + }