Skip to main content
summaryrefslogtreecommitdiffstats
blob: f75089a639004ea9774ee91070d98f10ba95fde5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*******************************************************************************
 * Copyright (c) 2005, 2012 Oracle. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0, which accompanies this distribution
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *     Oracle - initial API and implementation
 ******************************************************************************/
package org.eclipse.jpt.common.utility.internal.iterators;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.eclipse.jpt.common.utility.internal.StringTools;

/**
 * A <code>ResultSetIterator</code> wraps an SQL {@link ResultSet}
 * and transforms its rows for client consumption. Subclasses can override
 * {@link #buildNext(ResultSet)} to build the expected object from
 * the current row of the result set.
 * <p>
 * To use, supply:<ul>
 * <li> a {@link ResultSet}
 * <li> an {@link Adapter} that converts a row in the {@link ResultSet}
 * into the desired object
 * (alternatively, subclass <code>ResultSetIterator</code>
 * and override the {@link #buildNext(ResultSet)} method)
 * </ul>
 * 
 * @param <E> the type of elements returned by the iterator
 * 
 * @see java.sql.ResultSet
 */
public class ResultSetIterator<E>
	implements Iterator<E>
{
	private final ResultSet resultSet;
	private final Adapter<E> adapter;
	private E next;
	private boolean done;


	/**
	 * Construct an iterator on the specified result set that returns
	 * the objects produced by the specified adapter.
	 */
	public ResultSetIterator(ResultSet resultSet, Adapter<E> adapter) {
		super();
		this.resultSet = resultSet;
		this.adapter = adapter;
		this.done = false;
		this.next = this.buildNext();
	}

	/**
	 * Construct an iterator on the specified result set that returns
	 * the first object in each row of the result set.
	 */
	public ResultSetIterator(ResultSet resultSet) {
		this(resultSet, Adapter.Default.<E>instance());
	}

	/**
	 * Build the next object for the iterator to return.
	 * Close the result set when we reach the end.
	 */
	private E buildNext() {
		try {
			if (this.resultSet.next()) {
				return this.buildNext(this.resultSet);
			}
			this.resultSet.close();
			this.done = true;
			return null;
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	}

	/**
	 * By default, return the first object in the current row
	 * of the result set. Any {@link SQLException}s will
	 * be caught and wrapped in a {@link RuntimeException}.
	 */
	protected E buildNext(ResultSet rs) throws SQLException {
		return this.adapter.buildNext(rs);
	}

	public boolean hasNext() {
		return ! this.done;
	}

	public E next() {
		if (this.done) {
			throw new NoSuchElementException();
		}
		E temp = this.next;
		this.next = this.buildNext();
		return temp;
	}

	public void remove() {
		throw new UnsupportedOperationException();
	}

	@Override
	public String toString() {
		return StringTools.buildToStringFor(this, this.resultSet);
	}


	// ********** interface **********

	/**
	 * Used by {@link ResultSetIterator} to convert a
	 * {@link ResultSet}'s current row into the next object
	 * to be returned by the {@link Iterator}.
	 */
	public interface Adapter<T> {

		/**
		 * Return an object corresponding to the result set's
		 * "current" row. Any {@link SQLException}s will
		 * be caught and wrapped in a {@link RuntimeException}.
		 * @see java.sql.ResultSet
		 */
		T buildNext(ResultSet rs) throws SQLException;


		final class Default<S>
			implements Adapter<S>, Serializable
		{
			@SuppressWarnings("rawtypes")
			public static final Adapter INSTANCE = new Default();
			@SuppressWarnings("unchecked")
			public static <R> Adapter<R> instance() {
				return INSTANCE;
			}
			// ensure single instance
			private Default() {
				super();
			}
			// return the first object in the current row of the result set
			@SuppressWarnings("unchecked")
			public S buildNext(ResultSet rs) throws SQLException {
				// result set columns are indexed starting with 1
				return (S) rs.getObject(1);
			}
			@Override
			public String toString() {
				return StringTools.buildSingletonToString(this);
			}
			private static final long serialVersionUID = 1L;
			private Object readResolve() {
				// replace this object with the singleton
				return INSTANCE;
			}
		}
	}
}

Back to the top