class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {

	private PreparedStatement preparedStatement;

	private PreparedStatementSetter preparedStatementSetter;

	private String sql;

	private RowMapper<T> rowMapper;

	public JdbcCursorItemReader() {
		super();
		setName(ClassUtils.getShortName(JdbcCursorItemReader.class));
	}

	/**
	 * Set the RowMapper to be used for all calls to read().
	 * @param rowMapper the mapper used to map each item
	 */
	public void setRowMapper(RowMapper<T> rowMapper) {
		this.rowMapper = rowMapper;
	}

	/**
	 * Set the SQL statement to be used when creating the cursor. This statement should be
	 * a complete and valid SQL statement, as it will be run directly without any
	 * modification.
	 * @param sql SQL statement
	 */
	public void setSql(String sql) {
		this.sql = sql;
	}

	/**
	 * Set the PreparedStatementSetter to use if any parameter values that need to be set
	 * in the supplied query.
	 * @param preparedStatementSetter PreparedStatementSetter responsible for filling out
	 * the statement
	 */
	public void setPreparedStatementSetter(PreparedStatementSetter preparedStatementSetter) {
		this.preparedStatementSetter = preparedStatementSetter;
	}

	/**
	 * Assert that mandatory properties are set.
	 * @throws IllegalArgumentException if either data source or SQL properties not set.
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		Assert.state(sql != null, "The SQL query must be provided");
		Assert.state(rowMapper != null, "RowMapper must be provided");
	}

	@Override
	protected void openCursor(Connection con) {<FILL_FUNCTION_BODY>}

	@Nullable
	@Override
	protected T readCursor(ResultSet rs, int currentRow) throws SQLException {
		return rowMapper.mapRow(rs, currentRow);
	}

	/**
	 * Close the cursor and database connection.
	 * @param connection to the database
	 */
	@Override
	protected void cleanupOnClose(Connection connection) {
		JdbcUtils.closeStatement(this.preparedStatement);
		JdbcUtils.closeConnection(connection);
	}

	@Override
	public String getSql() {
		return this.sql;
	}

}

		try {
			if (isUseSharedExtendedConnection()) {
				preparedStatement = con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
						ResultSet.HOLD_CURSORS_OVER_COMMIT);
			}
			else {
				preparedStatement = con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
			}
			applyStatementSettings(preparedStatement);
			if (this.preparedStatementSetter != null) {
				preparedStatementSetter.setValues(preparedStatement);
			}
			this.rs = preparedStatement.executeQuery();
			handleWarnings(preparedStatement);
		}
		catch (SQLException se) {
			close();
			throw translateSqlException("Executing query", getSql(), se);
		}

	
<methods>public void <init>() ,public void afterPropertiesSet() throws java.lang.Exception,public javax.sql.DataSource getDataSource() ,public abstract java.lang.String getSql() ,public boolean isUseSharedExtendedConnection() ,public void setConnectionAutoCommit(boolean) ,public void setDataSource(javax.sql.DataSource) ,public void setDriverSupportsAbsolute(boolean) ,public void setFetchSize(int) ,public void setIgnoreWarnings(boolean) ,public void setMaxRows(int) ,public void setQueryTimeout(int) ,public void setUseSharedExtendedConnection(boolean) ,public void setVerifyCursorPosition(boolean) <variables>public static final int VALUE_NOT_SET,private java.sql.Connection con,private java.lang.Boolean connectionAutoCommit,private javax.sql.DataSource dataSource,private boolean driverSupportsAbsolute,private org.springframework.jdbc.support.SQLExceptionTranslator exceptionTranslator,private int fetchSize,private boolean ignoreWarnings,private boolean initialConnectionAutoCommit,private boolean initialized,protected final org.apache.commons.logging.Log log,private int maxRows,private int queryTimeout,protected java.sql.ResultSet rs,private boolean useSharedExtendedConnection,private boolean verifyCursorPosition