Skip to content

Commit 15eec87

Browse files
mminellacppwfs
authored andcommitted
Adding autoconfiguration for a JdbcCursorItemReader
This commit adds autoconfiguration for a JdbcCursorItemReader to the single step batch job starter. Fixed build Updates updated to clean db between tests
1 parent 468fab1 commit 15eec87

File tree

5 files changed

+747
-2
lines changed

5 files changed

+747
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright 2020-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.task.batch.autoconfigure.jdbc;
18+
19+
import java.sql.ResultSet;
20+
import java.sql.SQLException;
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
24+
import javax.sql.DataSource;
25+
26+
import org.springframework.batch.item.database.JdbcCursorItemReader;
27+
import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder;
28+
import org.springframework.beans.factory.annotation.Autowired;
29+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
30+
import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
32+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
33+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
34+
import org.springframework.context.annotation.Bean;
35+
import org.springframework.context.annotation.Configuration;
36+
import org.springframework.jdbc.core.PreparedStatementSetter;
37+
import org.springframework.jdbc.core.RowMapper;
38+
39+
/**
40+
* @author Michael Minella
41+
* @since 2.3
42+
*/
43+
@Configuration
44+
@EnableConfigurationProperties(JdbcCursorItemReaderProperties.class)
45+
@AutoConfigureAfter(BatchAutoConfiguration.class)
46+
@ConditionalOnProperty(prefix = "spring.batch.job.jdbccursorreader", name = "name")
47+
public class JdbcCursorItemReaderAutoConfiguration {
48+
49+
private final JdbcCursorItemReaderProperties properties;
50+
51+
private final DataSource dataSource;
52+
53+
@Autowired(required = false)
54+
private PreparedStatementSetter preparedStatementSetter;
55+
56+
@Autowired(required = false)
57+
private RowMapper<Map<Object, Object>> rowMapper;
58+
59+
public JdbcCursorItemReaderAutoConfiguration(
60+
JdbcCursorItemReaderProperties properties, DataSource dataSource) {
61+
this.properties = properties;
62+
this.dataSource = dataSource;
63+
}
64+
65+
@Bean
66+
@ConditionalOnMissingBean
67+
public JdbcCursorItemReader<Map<Object, Object>> itemReader() {
68+
return new JdbcCursorItemReaderBuilder<Map<Object, Object>>()
69+
.name(this.properties.getName())
70+
.currentItemCount(this.properties.getCurrentItemCount())
71+
.dataSource(this.dataSource)
72+
.driverSupportsAbsolute(this.properties.isDriverSupportsAbsolute())
73+
.fetchSize(this.properties.getFetchSize())
74+
.ignoreWarnings(this.properties.isIgnoreWarnings())
75+
.maxItemCount(this.properties.getMaxItemCount())
76+
.maxRows(this.properties.getMaxRows())
77+
.queryTimeout(this.properties.getQueryTimeout())
78+
.saveState(this.properties.isSaveState()).sql(this.properties.getSql())
79+
.rowMapper(this.rowMapper)
80+
.preparedStatementSetter(this.preparedStatementSetter)
81+
.verifyCursorPosition(this.properties.isVerifyCursorPosition())
82+
.useSharedExtendedConnection(
83+
this.properties.isUseSharedExtendedConnection())
84+
.build();
85+
}
86+
87+
@Bean
88+
@ConditionalOnMissingBean
89+
public RowMapper<Map<Object, Object>> rowMapper() {
90+
return new MapRowMapper();
91+
}
92+
93+
public static class MapRowMapper implements RowMapper<Map<Object, Object>> {
94+
95+
@Override
96+
public Map<Object, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
97+
Map<Object, Object> item = new HashMap<>(rs.getMetaData().getColumnCount());
98+
99+
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
100+
item.put(rs.getMetaData().getColumnName(i), rs.getObject(i));
101+
}
102+
103+
return item;
104+
}
105+
106+
}
107+
108+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
/*
2+
* Copyright 2020-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.task.batch.autoconfigure.jdbc;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
/**
22+
* @author Michael Minella
23+
* @since 2.3
24+
*/
25+
@ConfigurationProperties(prefix = "spring.batch.job.jdbccursorreader")
26+
public class JdbcCursorItemReaderProperties {
27+
28+
private boolean saveState = true;
29+
30+
private String name;
31+
32+
private int maxItemCount = Integer.MAX_VALUE;
33+
34+
private int currentItemCount = 0;
35+
36+
private int fetchSize;
37+
38+
private int maxRows;
39+
40+
private int queryTimeout;
41+
42+
private boolean ignoreWarnings;
43+
44+
private boolean verifyCursorPosition;
45+
46+
private boolean driverSupportsAbsolute;
47+
48+
private boolean useSharedExtendedConnection;
49+
50+
private String sql;
51+
52+
/**
53+
* Returns the configured value of if the state of the reader will be persisted.
54+
* @return true if the state will be persisted
55+
*/
56+
public boolean isSaveState() {
57+
return this.saveState;
58+
}
59+
60+
/**
61+
* Configure if the state of the
62+
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
63+
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
64+
* @param saveState defaults to true
65+
*/
66+
public void setSaveState(boolean saveState) {
67+
this.saveState = saveState;
68+
}
69+
70+
/**
71+
* Returns the configured value of the name used to calculate {@code ExecutionContext}
72+
* keys.
73+
* @return the name
74+
*/
75+
public String getName() {
76+
return this.name;
77+
}
78+
79+
/**
80+
* The name used to calculate the key within the
81+
* {@link org.springframework.batch.item.ExecutionContext}. Required if
82+
* {@link #setSaveState} is set to true.
83+
* @param name name of the reader instance
84+
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
85+
*/
86+
public void setName(String name) {
87+
this.name = name;
88+
}
89+
90+
/**
91+
* The maximum number of items to be read.
92+
* @return the configured number of items, defaults to Integer.MAX_VALUE
93+
*/
94+
public int getMaxItemCount() {
95+
return this.maxItemCount;
96+
}
97+
98+
/**
99+
* Configure the max number of items to be read.
100+
* @param maxItemCount the max items to be read
101+
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
102+
*/
103+
public void setMaxItemCount(int maxItemCount) {
104+
this.maxItemCount = maxItemCount;
105+
}
106+
107+
/**
108+
* Provides the index of the current item.
109+
* @return item index
110+
*/
111+
public int getCurrentItemCount() {
112+
return this.currentItemCount;
113+
}
114+
115+
/**
116+
* Index for the current item. Also used on restarts to indicate where to start from.
117+
* @param currentItemCount current index
118+
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
119+
*/
120+
public void setCurrentItemCount(int currentItemCount) {
121+
this.currentItemCount = currentItemCount;
122+
}
123+
124+
/**
125+
* Provides the number of items to return each time the cursor fetches from the
126+
* server.
127+
* @return fetch size
128+
*/
129+
public int getFetchSize() {
130+
return fetchSize;
131+
}
132+
133+
/**
134+
* Sets the number of items to return each time the cursor fetches from the server.
135+
* @param fetchSize the number of items
136+
* @see org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder#fetchSize(int)
137+
*/
138+
public void setFetchSize(int fetchSize) {
139+
this.fetchSize = fetchSize;
140+
}
141+
142+
/**
143+
* Provides the maximum number of rows to read with this reader.
144+
* @return maxiumum number of items
145+
*/
146+
public int getMaxRows() {
147+
return maxRows;
148+
}
149+
150+
/**
151+
* Sets the maximum number of rows to be read with this reader.
152+
* @param maxRows maximum number of items
153+
* @see org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder#maxRows(int)
154+
*/
155+
public void setMaxRows(int maxRows) {
156+
this.maxRows = maxRows;
157+
}
158+
159+
/**
160+
* Provides the time in milliseconds for the query to timeout.
161+
* @return milliseconds for the timeout
162+
*/
163+
public int getQueryTimeout() {
164+
return queryTimeout;
165+
}
166+
167+
/**
168+
* Sets the time in milliseconds for the query to timeout.
169+
* @param queryTimeout milliseconds
170+
* @see org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder#queryTimeout(int)
171+
*/
172+
public void setQueryTimeout(int queryTimeout) {
173+
this.queryTimeout = queryTimeout;
174+
}
175+
176+
/**
177+
* Provides if SQL warnings should be ignored.
178+
* @return true if warnings should be ignored
179+
*/
180+
public boolean isIgnoreWarnings() {
181+
return ignoreWarnings;
182+
}
183+
184+
/**
185+
* Sets if SQL warnings should be ignored.
186+
* @param ignoreWarnings indicator if the warnings should be ignored
187+
* @see org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder#ignoreWarnings(boolean)
188+
*/
189+
public void setIgnoreWarnings(boolean ignoreWarnings) {
190+
this.ignoreWarnings = ignoreWarnings;
191+
}
192+
193+
/**
194+
* Indicates if the cursor's position should be validated with each item read (to
195+
* confirm that the RowMapper has not moved the cursor's location).
196+
* @return true if the position should be validated
197+
*/
198+
public boolean isVerifyCursorPosition() {
199+
return verifyCursorPosition;
200+
}
201+
202+
/**
203+
* Provides if the cursor's position should be validated with each item read.
204+
* @param verifyCursorPosition true if the position should be validated
205+
* @see org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder#verifyCursorPosition(boolean)
206+
*/
207+
public void setVerifyCursorPosition(boolean verifyCursorPosition) {
208+
this.verifyCursorPosition = verifyCursorPosition;
209+
}
210+
211+
/**
212+
* Provides if the driver supports absolute positioning of a cursor.
213+
* @return true if the driver supports absolute positioning
214+
*/
215+
public boolean isDriverSupportsAbsolute() {
216+
return driverSupportsAbsolute;
217+
}
218+
219+
/**
220+
* Sets if the driver supports absolute positioning of a cursor.
221+
* @param driverSupportsAbsolute true if the driver supports absolute positioning
222+
* @see org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder#driverSupportsAbsolute(boolean)
223+
*/
224+
public void setDriverSupportsAbsolute(boolean driverSupportsAbsolute) {
225+
this.driverSupportsAbsolute = driverSupportsAbsolute;
226+
}
227+
228+
/**
229+
* Provides if the the connection used for the cursor is being used by all other
230+
* processing, therefor part of the same transaction.
231+
* @return true if the connection is shared beyond this query
232+
*/
233+
public boolean isUseSharedExtendedConnection() {
234+
return useSharedExtendedConnection;
235+
}
236+
237+
/**
238+
* Sets if the the connection used for the cursor is being used by all other
239+
* processing, therefor part of the same transaction.
240+
* @param useSharedExtendedConnection true if the connection is shared beyond this
241+
* query
242+
* @see org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder#useSharedExtendedConnection(boolean)
243+
*/
244+
public void setUseSharedExtendedConnection(boolean useSharedExtendedConnection) {
245+
this.useSharedExtendedConnection = useSharedExtendedConnection;
246+
}
247+
248+
/**
249+
* Returns the SQL query to be executed.
250+
* @return the SQL query
251+
*/
252+
public String getSql() {
253+
return sql;
254+
}
255+
256+
/**
257+
* Sets the SQL query to be executed.
258+
* @param sql the query
259+
* @see org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder#sql(String)
260+
*/
261+
public void setSql(String sql) {
262+
this.sql = sql;
263+
}
264+
265+
}

spring-cloud-starter-single-step-batch-job/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframewo
22
org.springframework.cloud.task.batch.autoconfigure.RangeConverter,\
33
org.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration,\
44
org.springframework.cloud.task.batch.autoconfigure.FlatFileItemWriterAutoConfiguration, \
5-
org.springframework.cloud.task.batch.autoconfigure.jdbc.JdbcItemWriterAutoConfiguration
5+
org.springframework.cloud.task.batch.autoconfigure.jdbc.JdbcItemWriterAutoConfiguration, \
6+
org.springframework.cloud.task.batch.autoconfigure.jdbc.JdbcCursorItemReaderAutoConfiguration

0 commit comments

Comments
 (0)