1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.dbutils;
18
19 import java.sql.ResultSet;
20 import java.sql.SQLException;
21 import java.util.Iterator;
22
23 /**
24 * <p>
25 * Wraps a {@code ResultSet} in an {@code Iterator<Object[]>}. This is useful
26 * when you want to present a non-database application layer with domain
27 * neutral data.
28 * </p>
29 *
30 * <p>
31 * This implementation requires the {@code ResultSet.isLast()} method
32 * to be implemented.
33 * </p>
34 */
35 public class ResultSetIterator implements Iterator<Object[]> {
36
37 /**
38 * Generates an {@code Iterable}, suitable for use in for-each loops.
39 *
40 * @param resultSet Wrap this {@code ResultSet} in an {@code Iterator}.
41 * @return an {@code Iterable}, suitable for use in for-each loops.
42 */
43 public static Iterable<Object[]> iterable(final ResultSet resultSet) {
44 return () -> new ResultSetIterator(resultSet);
45 }
46
47 /**
48 * The wrapped {@code ResultSet}.
49 */
50 private final ResultSet resultSet;
51
52 /**
53 * The processor to use when converting a row into an Object[].
54 */
55 private final RowProcessor convert;
56
57 /**
58 * Constructor for ResultSetIterator.
59 * @param resultSet Wrap this {@code ResultSet} in an {@code Iterator}.
60 */
61 public ResultSetIterator(final ResultSet resultSet) {
62 this(resultSet, new BasicRowProcessor());
63 }
64
65 /**
66 * Constructor for ResultSetIterator.
67 * @param resultSet Wrap this {@code ResultSet} in an {@code Iterator}.
68 * @param convert The processor to use when converting a row into an
69 * {@code Object[]}. Defaults to a
70 * {@code BasicRowProcessor}.
71 */
72 public ResultSetIterator(final ResultSet resultSet, final RowProcessor convert) {
73 this.resultSet = resultSet;
74 this.convert = convert;
75 }
76
77 /**
78 * Returns true if there are more rows in the ResultSet.
79 * @return boolean {@code true} if there are more rows
80 * @throws RuntimeException if an SQLException occurs.
81 */
82 @Override
83 public boolean hasNext() {
84 try {
85 return !resultSet.isLast();
86 } catch (final SQLException e) {
87 rethrow(e);
88 return false;
89 }
90 }
91
92 /**
93 * Returns the next row as an {@code Object[]}.
94 * @return An {@code Object[]} with the same number of elements as
95 * columns in the {@code ResultSet}.
96 * @see java.util.Iterator#next()
97 * @throws RuntimeException if an SQLException occurs.
98 */
99 @Override
100 public Object[] next() {
101 try {
102 resultSet.next();
103 return this.convert.toArray(resultSet);
104 } catch (final SQLException e) {
105 rethrow(e);
106 return null;
107 }
108 }
109
110 /**
111 * Deletes the current row from the {@code ResultSet}.
112 * @see java.util.Iterator#remove()
113 * @throws RuntimeException if an SQLException occurs.
114 */
115 @Override
116 public void remove() {
117 try {
118 this.resultSet.deleteRow();
119 } catch (final SQLException e) {
120 rethrow(e);
121 }
122 }
123
124 /**
125 * Rethrow the SQLException as a RuntimeException. This implementation
126 * creates a new RuntimeException with the SQLException's error message.
127 * @param e SQLException to rethrow
128 * @since 1.1
129 */
130 protected void rethrow(final SQLException e) {
131 throw new RuntimeException(e.getMessage());
132 }
133
134 }