class JpaCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> implements InitializingBean {

	private EntityManagerFactory entityManagerFactory;

	private EntityManager entityManager;

	private String queryString;

	private JpaQueryProvider queryProvider;

	private Map<String, Object> parameterValues;

	private Map<String, Object> hintValues;

	private Iterator<T> iterator;

	/**
	 * Create a new {@link JpaCursorItemReader}.
	 */
	public JpaCursorItemReader() {
		setName(ClassUtils.getShortName(JpaCursorItemReader.class));
	}

	/**
	 * Set the JPA entity manager factory.
	 * @param entityManagerFactory JPA entity manager factory
	 */
	public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
		this.entityManagerFactory = entityManagerFactory;
	}

	/**
	 * Set the JPA query provider.
	 * @param queryProvider JPA query provider
	 */
	public void setQueryProvider(JpaQueryProvider queryProvider) {
		this.queryProvider = queryProvider;
	}

	/**
	 * Set the JPQL query string.
	 * @param queryString JPQL query string
	 */
	public void setQueryString(String queryString) {
		this.queryString = queryString;
	}

	/**
	 * Set the parameter values to be used for the query execution.
	 * @param parameterValues the values keyed by parameter names used in the query
	 * string.
	 */
	public void setParameterValues(Map<String, Object> parameterValues) {
		this.parameterValues = parameterValues;
	}

	/**
	 * Set the query hint values for the JPA query. Query hints can be used to give
	 * instructions to the JPA provider.
	 * @param hintValues a map where each key is the name of the hint, and the
	 * corresponding value is the hint's value.
	 * @since 5.2
	 */
	public void setHintValues(Map<String, Object> hintValues) {
		this.hintValues = hintValues;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.state(this.entityManagerFactory != null, "EntityManagerFactory is required");
		if (this.queryProvider == null) {
			Assert.state(StringUtils.hasLength(this.queryString),
					"Query string is required when queryProvider is null");
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	protected void doOpen() throws Exception {
		this.entityManager = this.entityManagerFactory.createEntityManager();
		if (this.entityManager == null) {
			throw new DataAccessResourceFailureException("Unable to create an EntityManager");
		}
		if (this.queryProvider != null) {
			this.queryProvider.setEntityManager(this.entityManager);
		}
		Query query = createQuery();
		if (this.parameterValues != null) {
			this.parameterValues.forEach(query::setParameter);
		}
		if (this.hintValues != null) {
			this.hintValues.forEach(query::setHint);
		}

		this.iterator = query.getResultStream().iterator();
	}

	private Query createQuery() {<FILL_FUNCTION_BODY>}

	@Override
	protected T doRead() {
		return this.iterator.hasNext() ? this.iterator.next() : null;
	}

	@Override
	public void update(ExecutionContext executionContext) throws ItemStreamException {
		super.update(executionContext);
		this.entityManager.clear();
	}

	@Override
	protected void doClose() {
		if (this.entityManager != null) {
			this.entityManager.close();
		}
	}

}

		if (this.queryProvider == null) {
			return this.entityManager.createQuery(this.queryString);
		}
		else {
			return this.queryProvider.createQuery();
		}
	
<methods>public non-sealed void <init>() ,public void close() throws org.springframework.batch.item.ItemStreamException,public int getCurrentItemCount() ,public boolean isSaveState() ,public void open(org.springframework.batch.item.ExecutionContext) throws org.springframework.batch.item.ItemStreamException,public T read() throws java.lang.Exception,public void setCurrentItemCount(int) ,public void setMaxItemCount(int) ,public void setSaveState(boolean) ,public void update(org.springframework.batch.item.ExecutionContext) throws org.springframework.batch.item.ItemStreamException<variables>private static final java.lang.String READ_COUNT,private static final java.lang.String READ_COUNT_MAX,private int currentItemCount,private int maxItemCount,private boolean saveState