class SingleItemPeekableItemReader<T> implements ItemStreamReader<T>, PeekableItemReader<T> {

	private ItemReader<T> delegate;

	private T next;

	private ExecutionContext executionContext = new ExecutionContext();

	/**
	 * The item reader to use as a delegate. Items are read from the delegate and passed
	 * to the caller in {@link #read()}.
	 * @param delegate the delegate to set
	 */
	public void setDelegate(ItemReader<T> delegate) {
		this.delegate = delegate;
	}

	/**
	 * Get the next item from the delegate (whether or not it has already been peeked at).
	 *
	 * @see ItemReader#read()
	 */
	@Nullable
	@Override
	public T read() throws Exception {
		if (next != null) {
			T item = next;
			next = null;
			return item;
		}
		return delegate.read();
	}

	/**
	 * Peek at the next item, ensuring that if the delegate is an {@link ItemStream} the
	 * state is stored for the next call to {@link #update(ExecutionContext)}.
	 * @return the next item (or null if there is none).
	 *
	 * @see PeekableItemReader#peek()
	 */
	@Nullable
	@Override
	public T peek() throws Exception {
		if (next == null) {
			updateDelegate(executionContext);
			next = delegate.read();
		}
		return next;
	}

	/**
	 * If the delegate is an {@link ItemStream}, just pass the call on, otherwise reset
	 * the peek cache.
	 * @throws ItemStreamException if there is a problem
	 * @see ItemStream#close()
	 */
	@Override
	public void close() throws ItemStreamException {
		next = null;
		if (delegate instanceof ItemStream) {
			((ItemStream) delegate).close();
		}
		executionContext = new ExecutionContext();
	}

	/**
	 * If the delegate is an {@link ItemStream}, just pass the call on, otherwise reset
	 * the peek cache.
	 * @param executionContext the current context
	 * @throws ItemStreamException if there is a problem
	 * @see ItemStream#open(ExecutionContext)
	 */
	@Override
	public void open(ExecutionContext executionContext) throws ItemStreamException {
		next = null;
		if (delegate instanceof ItemStream) {
			((ItemStream) delegate).open(executionContext);
		}
		executionContext = new ExecutionContext();
	}

	/**
	 * If there is a cached peek, then retrieve the execution context state from that
	 * point. If there is no peek cached, then call directly to the delegate.
	 * @param executionContext the current context
	 * @throws ItemStreamException if there is a problem
	 * @see ItemStream#update(ExecutionContext)
	 */
	@Override
	public void update(ExecutionContext executionContext) throws ItemStreamException {<FILL_FUNCTION_BODY>}

	private void updateDelegate(ExecutionContext executionContext) {
		if (delegate instanceof ItemStream) {
			((ItemStream) delegate).update(executionContext);
		}
	}

}

		if (next != null) {
			// Get the last state from the delegate instead of using
			// current value.
			for (Entry<String, Object> entry : this.executionContext.entrySet()) {
				executionContext.put(entry.getKey(), entry.getValue());
			}
			return;
		}
		updateDelegate(executionContext);
	
<no_super_class>