diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcCursorItemReaderBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcCursorItemReaderBuilder.java index 980ae932c..69903eddb 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcCursorItemReaderBuilder.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcCursorItemReaderBuilder.java @@ -25,6 +25,7 @@ import org.springframework.jdbc.core.ArgumentTypePreparedStatementSetter; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.PreparedStatementSetter; import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.DataClassRowMapper; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -38,6 +39,7 @@ import org.springframework.util.StringUtils; * @author Ankur Trapasiya * @author Parikshit Dutta * @author Fabio Molignoni + * @author Juyoung Kim * @since 4.0 */ public class JdbcCursorItemReaderBuilder { @@ -312,6 +314,18 @@ public class JdbcCursorItemReaderBuilder { return this; } + /** + * Creates a {@link DataClassRowMapper} to be used as your {@link RowMapper}. + * @param mappedClass the class for the row mapper + * @return this instance for method chaining + * @see DataClassRowMapper + */ + public JdbcCursorItemReaderBuilder dataRowMapper(Class mappedClass) { + this.rowMapper = new DataClassRowMapper<>(mappedClass); + + return this; + } + /** * Set whether "autoCommit" should be overridden for the connection used by the * cursor. If not set, defaults to Connection / Datasource default configuration. diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilder.java index 2f9cee1d1..0dc527902 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilder.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import org.springframework.batch.item.database.support.SqlitePagingQueryProvider import org.springframework.batch.item.database.support.SybasePagingQueryProvider; import org.springframework.batch.support.DatabaseType; import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.DataClassRowMapper; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.support.MetaDataAccessException; import org.springframework.util.Assert; @@ -52,6 +53,7 @@ import org.springframework.util.Assert; * @author Drummond Dawson * @author Mahmoud Ben Hassine * @author Minsoo Kim + * @author Juyoung Kim * @since 4.0 * @see JdbcPagingItemReader */ @@ -186,6 +188,18 @@ public class JdbcPagingItemReaderBuilder { return this; } + /** + * Creates a {@link DataClassRowMapper} to be used as your {@link RowMapper}. + * @param mappedClass the class for the row mapper + * @return this instance for method chaining + * @see DataClassRowMapper + */ + public JdbcPagingItemReaderBuilder dataRowMapper(Class mappedClass) { + this.rowMapper = new DataClassRowMapper<>(mappedClass); + + return this; + } + /** * A {@link Map} of values to set on the SQL's prepared statement. * @param parameterValues Map of values diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/JdbcCursorItemReaderBuilderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/JdbcCursorItemReaderBuilderTests.java index c8b2528e1..ba2566326 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/JdbcCursorItemReaderBuilderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/JdbcCursorItemReaderBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 the original author or authors. + * Copyright 2016-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,6 +47,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @author Ankur Trapasiya * @author Parikshit Dutta * @author Mahmoud Ben Hassine + * @author Juyoung Kim */ class JdbcCursorItemReaderBuilderTests { @@ -334,6 +335,29 @@ class JdbcCursorItemReaderBuilderTests { assertEquals(third, item.getThird()); } + @Test + void testDataRowMapper() throws Exception { + JdbcCursorItemReader reader = new JdbcCursorItemReaderBuilder() + .name("barReader") + .dataSource(this.dataSource) + .currentItemCount(1) + .maxItemCount(2) + .sql("SELECT ID, FIRST, SECOND, THIRD FROM BAR ORDER BY ID DESC") + .dataRowMapper(Bar.class) + .build(); + + reader.afterPropertiesSet(); + + reader.open(new ExecutionContext()); + Bar item1 = reader.read(); + assertNull(reader.read()); + + assertEquals(3, item1.id()); + assertEquals(10, item1.first()); + assertEquals("11", item1.second()); + assertEquals("12", item1.third()); + } + public static class Foo { private int first; @@ -368,6 +392,8 @@ class JdbcCursorItemReaderBuilderTests { } + public record Bar(int id, int first, String second, String third) {} + @Configuration public static class TestDataSourceConfiguration { @@ -376,12 +402,24 @@ class JdbcCursorItemReaderBuilderTests { ID BIGINT IDENTITY NOT NULL PRIMARY KEY , FIRST BIGINT , SECOND VARCHAR(5) NOT NULL, - THIRD VARCHAR(5) NOT NULL);"""; + THIRD VARCHAR(5) NOT NULL); + + CREATE TABLE BAR ( + ID BIGINT IDENTITY NOT NULL PRIMARY KEY , + FIRST BIGINT , + SECOND VARCHAR(5) NOT NULL, + THIRD VARCHAR(5) NOT NULL) ;"""; private static final String INSERT_SQL = """ INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (1, '2', '3'); INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (4, '5', '6'); - INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (7, '8', '9');"""; + INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (7, '8', '9'); + + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (1, '2', '3'); + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (4, '5', '6'); + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (7, '8', '9'); + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (10, '11', '12'); + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (13, '14', '15');"""; @Bean public DataSource dataSource() { diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilderTests.java index 47999e920..8061442cb 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,6 +47,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; * @author Michael Minella * @author Drummond Dawson * @author Mahmoud Ben Hassine + * @author Juyoung Kim */ class JdbcPagingItemReaderBuilderTests { @@ -262,6 +263,34 @@ class JdbcPagingItemReaderBuilderTests { assertEquals("12", item1.getThird()); } + @Test + void testDataRowMapper() throws Exception { + Map sortKeys = new HashMap<>(1); + sortKeys.put("ID", Order.DESCENDING); + + JdbcPagingItemReader reader = new JdbcPagingItemReaderBuilder() + .name("barReader") + .dataSource(this.dataSource) + .currentItemCount(1) + .maxItemCount(2) + .selectClause("SELECT ID, FIRST, SECOND, THIRD") + .fromClause("BAR") + .sortKeys(sortKeys) + .dataRowMapper(Bar.class) + .build(); + + reader.afterPropertiesSet(); + + reader.open(new ExecutionContext()); + Bar item1 = reader.read(); + assertNull(reader.read()); + + assertEquals(3, item1.id()); + assertEquals(10, item1.first()); + assertEquals("11", item1.second()); + assertEquals("12", item1.third()); + } + @Test void testValidation() { var builder = new JdbcPagingItemReaderBuilder(); @@ -354,6 +383,8 @@ class JdbcPagingItemReaderBuilderTests { } + public record Bar(int id, int first, String second, String third) {} + @Configuration public static class TestDataSourceConfiguration { @@ -362,6 +393,12 @@ class JdbcPagingItemReaderBuilderTests { ID BIGINT IDENTITY NOT NULL PRIMARY KEY , FIRST BIGINT , SECOND VARCHAR(5) NOT NULL, + THIRD VARCHAR(5) NOT NULL) ; + + CREATE TABLE BAR ( + ID BIGINT IDENTITY NOT NULL PRIMARY KEY , + FIRST BIGINT , + SECOND VARCHAR(5) NOT NULL, THIRD VARCHAR(5) NOT NULL) ;"""; private static final String INSERT_SQL = """ @@ -369,7 +406,13 @@ class JdbcPagingItemReaderBuilderTests { INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (4, '5', '6'); INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (7, '8', '9'); INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (10, '11', '12'); - INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (13, '14', '15');"""; + INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (13, '14', '15'); + + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (1, '2', '3'); + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (4, '5', '6'); + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (7, '8', '9'); + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (10, '11', '12'); + INSERT INTO BAR (FIRST, SECOND, THIRD) VALUES (13, '14', '15');"""; @Bean public DataSource dataSource() {