Implement toStream() in querymapper

This commit is contained in:
Travis Burtrum 2017-06-12 22:57:43 -04:00
parent c902da5126
commit 280e11b713
12 changed files with 344 additions and 22 deletions

View File

@ -24,4 +24,20 @@
<build>
<finalName>${project.artifactId}</finalName>
</build>
<profiles>
<profile>
<id>jdk16</id>
<activation>
<jdk>[1.6,1.8)</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -57,4 +57,18 @@ public class TryClose { // tries to close certain object types
// ignore...
}
}
//IFJAVA8_START
public static void tryClose(AutoCloseable obj) {
if (obj == null)
return;
try {
obj.close();
} catch (Throwable e) {
// ignore...
}
}
//IFJAVA8_END
}

View File

@ -7,6 +7,11 @@ import java.sql.SQLException;
import java.util.Calendar;
import java.util.Iterator;
import java.util.NoSuchElementException;
//IFJAVA8_START
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
//IFJAVA8_END
import static com.moparisthebest.jdbc.TryClose.tryClose;
@ -42,19 +47,49 @@ public class ResultSetIterable<T> implements Iterable<T>, Iterator<T>, Closeable
* ResultSetIterable<T> rsi = ResultSetIterable.getResultSetIterable(rs, rs.next() ? complicatedBuildResultSetToObject(rs) : null, cal);
* <p>
* This way you can avoid building or sending in a ResultSetToObject all together if there are no rows, therefore if rsto
* sent into this is null, it returns an EMPTY_RESULT_SET_ITERABLE
* sent into this is null, it returns an EMPTY_RESULT_SET_ITERABLE and closes rs immediately
* <p>
* This assumes rs.next() was called once before sent into this function
*/
@SuppressWarnings("unchecked")
public static <T> ResultSetIterable<T> getResultSetIterable(final ResultSet rs, final ResultSetToObject<T> rsto, final Calendar cal) {
if (rsto == null)
if (rsto == null) {
tryClose(rs); // have to do this here...
return (ResultSetIterable<T>) EMPTY_RESULT_SET_ITERABLE;
}
final ResultSetIterable<T> ret = new ResultSetIterable<T>(rs, rsto, cal);
ret.calledNext = true;
return ret;
}
/**
* This is a convenience method meant to be called like this, where rs is a ResultSet
* <p>
* Stream<T> rsi = ResultSetIterable.getStream(rs, rs.next() ? complicatedBuildResultSetToObject(rs) : null, cal);
* <p>
* This way you can avoid building or sending in a ResultSetToObject all together if there are no rows, therefore if rsto
* sent into this is null, it returns an empty Stream, rs might be closed before returning the empty Stream or on .close() to the Stream
* <p>
* The stream returned MUST be closed in a try-with-resources or finally because the ResultSet is held open until then
* <p>
* This assumes rs.next() was called once before sent into this function
*/
//IFJAVA8_START
@SuppressWarnings("unchecked")
public static <T> Stream<T> getStream(final ResultSet rs, final ResultSetToObject<T> rsto, final Calendar cal) {
final Stream<T> ret;
if (rsto == null) {
// todo: static object for this? don't forget to close resultset if so
return (Stream<T>) StreamSupport.stream(Spliterators.emptySpliterator(), false);
} else {
final ResultSetIterable<T> rsi = new ResultSetIterable<T>(rs, rsto, cal);
rsi.calledNext = true;
ret = StreamSupport.stream(rsi.spliterator(), false);
}
return ret.onClose(() -> tryClose(rs));
}
//IFJAVA8_END
private final ResultSet rs;
private final Calendar cal;
private final ResultSetToObject<T> rsto;

View File

@ -203,6 +203,7 @@
<configuration>
<includes>
<include>*/src/main/java/**/*</include>
<include>*/src/test/java/**/*</include>
</includes>
<excludes>
<exclude>target/**</exclude>

View File

@ -22,18 +22,22 @@ function finishFile(){
result="$(prepareFile "src/main/java/com/moparisthebest/jdbc/ResultSetMapper.java")"
# single object types
cat src/main/java/com/moparisthebest/jdbc/ResultSetMapper.java | grep public | egrep '(toObject|toSingleMap|toResultSetIterable|toResultSetIterableMap)\(' | grep ', Calendar cal)' | while read method
cat src/main/java/com/moparisthebest/jdbc/ResultSetMapper.java | grep public | egrep '(toObject|toSingleMap|toResultSetIterable|toStream)\(' | grep ', Calendar cal)' | while read method
do
#echo "method: $method"
method_name=$(echo $method | egrep -o '[^ ]+\(')
echo "ResultSetMapper.$method_name)"
[ "$method_name" == 'toStream(' ] && echo -e '\t//IFJAVA8_START\n' >> "$result"
cat >> "$result" <<EOF
$(echo $method | sed "s/, Calendar cal)/)/")
return this.$method_name$(echo $method | sed -e 's/^.*(//' -e 's/final //g' -e 's/, [^ ]* /, /g' -e 's/ResultSet rs/rs/' -e 's/) {/);/')
}
EOF
[ "$method_name" == 'toStream(' ] && echo -e '\t//IFJAVA8_END\n' >> "$result"
done
#everything else
@ -67,6 +71,8 @@ do
method_name=$(echo $method | egrep -o '[^ ]+\(')
echo "QueryMapper.$method_name)"
[ "$method_name" == 'toStream(' ] && echo -e '\t//IFJAVA8_START\n' | tee -a "$query" "$caching_query" "$null_query" "$list_query" >/dev/null
# QueryMapper.java
cat >> "$query" <<EOF
$(echo $method | sed -e 's/ResultSet rs/PreparedStatement ps/' -e 's/) {/, final Object... bindObjects) throws SQLException {/')
@ -76,7 +82,7 @@ do
EOF
# handle this specially in QueryMapper because we need it to hold open PreparedStatement until the ResultSetIterable is closed
if [ "$method_name" != 'toResultSetIterable(' -a "$method_name" != 'toResultSetIterableMap(' ]; then
if [ "$method_name" != 'toResultSetIterable(' -a "$method_name" != 'toStream(' ]; then
cat >> "$query" <<EOF
$(echo $method | sed -e 's/ResultSet rs/String sql/' -e 's/) {/, final Object... bindObjects) throws SQLException {/')
@ -91,7 +97,7 @@ EOF
EOF
fi # end special case toResultSetIterable
fi # end special case toResultSetIterable/toStream
# CachingQueryMapper.java
cat >> "$caching_query" <<EOF
@ -133,6 +139,9 @@ EOF
}
EOF
[ "$method_name" == 'toStream(' ] && echo -e '\t//IFJAVA8_END\n' | tee -a "$query" "$caching_query" "$null_query" "$list_query" >/dev/null
done
finishFile "src/main/java/com/moparisthebest/jdbc/QueryMapper.java"

View File

@ -50,4 +50,20 @@
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>jdk16</id>
<activation>
<jdk>[1.6,1.8)</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -7,6 +7,9 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
//IFJAVA8_START
import java.util.stream.Stream;
//IFJAVA8_END
import static com.moparisthebest.jdbc.TryClose.tryClose;
@ -145,10 +148,28 @@ public class CachingQueryMapper extends QueryMapper {
}
@Override
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterableMap(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return super.toResultSetIterableMap(getPreparedStatement(sql), componentType, mapValType, bindObjects);
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterable(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return super.toResultSetIterable(getPreparedStatement(sql), componentType, mapValType, bindObjects);
}
//IFJAVA8_START
@Override
public <T> Stream<T> toStream(String sql, Class<T> componentType, final Object... bindObjects) throws SQLException {
return super.toStream(getPreparedStatement(sql), componentType, bindObjects);
}
//IFJAVA8_END
//IFJAVA8_START
@Override
public <T extends Map<String, V>, V> Stream<Map<String, V>> toStream(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return super.toStream(getPreparedStatement(sql), componentType, mapValType, bindObjects);
}
//IFJAVA8_END
@Override
public <T extends Map<String, V>, V> Map<String, V> toSingleMap(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return super.toSingleMap(getPreparedStatement(sql), componentType, mapValType, bindObjects);

View File

@ -8,6 +8,9 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
//IFJAVA8_START
import java.util.stream.Stream;
//IFJAVA8_END
public class ListQueryMapper extends QueryMapper {
@ -253,15 +256,43 @@ public class ListQueryMapper extends QueryMapper {
}
@Override
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterableMap(PreparedStatement ps, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return delegate.toResultSetIterableMap(ps, componentType, mapValType, bindObjects);
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterable(PreparedStatement ps, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return delegate.toResultSetIterable(ps, componentType, mapValType, bindObjects);
}
@Override
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterableMap(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return delegate.toResultSetIterableMap(prepareSql(sql, bindObjects), componentType, mapValType, bindObjects);
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterable(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return delegate.toResultSetIterable(prepareSql(sql, bindObjects), componentType, mapValType, bindObjects);
}
//IFJAVA8_START
@Override
public <T> Stream<T> toStream(PreparedStatement ps, Class<T> componentType, final Object... bindObjects) throws SQLException {
return delegate.toStream(ps, componentType, bindObjects);
}
@Override
public <T> Stream<T> toStream(String sql, Class<T> componentType, final Object... bindObjects) throws SQLException {
return delegate.toStream(prepareSql(sql, bindObjects), componentType, bindObjects);
}
//IFJAVA8_END
//IFJAVA8_START
@Override
public <T extends Map<String, V>, V> Stream<Map<String, V>> toStream(PreparedStatement ps, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return delegate.toStream(ps, componentType, mapValType, bindObjects);
}
@Override
public <T extends Map<String, V>, V> Stream<Map<String, V>> toStream(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return delegate.toStream(prepareSql(sql, bindObjects), componentType, mapValType, bindObjects);
}
//IFJAVA8_END
@Override
public <T extends Map<String, V>, V> Map<String, V> toSingleMap(PreparedStatement ps, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return delegate.toSingleMap(ps, componentType, mapValType, bindObjects);

View File

@ -7,6 +7,9 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
//IFJAVA8_START
import java.util.stream.Stream;
//IFJAVA8_END
public class NullQueryMapper extends QueryMapper {
@ -280,9 +283,9 @@ public class NullQueryMapper extends QueryMapper {
}
@Override
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterableMap(PreparedStatement query, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) {
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterable(PreparedStatement query, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) {
try {
return delegate.toResultSetIterableMap(query, componentType, mapValType, bindObjects);
return delegate.toResultSetIterable(query, componentType, mapValType, bindObjects);
} catch (Throwable e) {
if (verbose) e.printStackTrace();
}
@ -290,15 +293,63 @@ public class NullQueryMapper extends QueryMapper {
}
@Override
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterableMap(String query, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) {
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterable(String query, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) {
try {
return delegate.toResultSetIterableMap(query, componentType, mapValType, bindObjects);
return delegate.toResultSetIterable(query, componentType, mapValType, bindObjects);
} catch (Throwable e) {
if (verbose) e.printStackTrace();
}
return null;
}
//IFJAVA8_START
@Override
public <T> Stream<T> toStream(PreparedStatement query, Class<T> componentType, final Object... bindObjects) {
try {
return delegate.toStream(query, componentType, bindObjects);
} catch (Throwable e) {
if (verbose) e.printStackTrace();
}
return null;
}
@Override
public <T> Stream<T> toStream(String query, Class<T> componentType, final Object... bindObjects) {
try {
return delegate.toStream(query, componentType, bindObjects);
} catch (Throwable e) {
if (verbose) e.printStackTrace();
}
return null;
}
//IFJAVA8_END
//IFJAVA8_START
@Override
public <T extends Map<String, V>, V> Stream<Map<String, V>> toStream(PreparedStatement query, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) {
try {
return delegate.toStream(query, componentType, mapValType, bindObjects);
} catch (Throwable e) {
if (verbose) e.printStackTrace();
}
return null;
}
@Override
public <T extends Map<String, V>, V> Stream<Map<String, V>> toStream(String query, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) {
try {
return delegate.toStream(query, componentType, mapValType, bindObjects);
} catch (Throwable e) {
if (verbose) e.printStackTrace();
}
return null;
}
//IFJAVA8_END
@Override
public <T extends Map<String, V>, V> Map<String, V> toSingleMap(PreparedStatement query, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) {
try {

View File

@ -9,6 +9,9 @@ import java.io.*;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.*;
//IFJAVA8_START
import java.util.stream.Stream;
//IFJAVA8_END
import static com.moparisthebest.jdbc.TryClose.tryClose;
@ -362,7 +365,7 @@ public class QueryMapper implements Closeable {
}
}
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterableMap(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterable(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
boolean error = true;
PreparedStatement ps = null;
ResultSet rs = null;
@ -370,7 +373,7 @@ public class QueryMapper implements Closeable {
try {
ps = conn.prepareStatement(sql);
rs = this.toResultSet(ps, bindObjects);
ret = cm.toResultSetIterableMap(rs, componentType, mapValType).setPreparedStatementToClose(ps);
ret = cm.toResultSetIterable(rs, componentType, mapValType).setPreparedStatementToClose(ps);
error = false;
return ret;
} finally {
@ -382,6 +385,50 @@ public class QueryMapper implements Closeable {
}
}
//IFJAVA8_START
public <T> Stream<T> toStream(String sql, Class<T> componentType, final Object... bindObjects) throws SQLException {
boolean error = true;
PreparedStatement ps = null;
ResultSet rs = null;
Stream<T> ret = null;
try {
ps = conn.prepareStatement(sql);
rs = this.toResultSet(ps, bindObjects);
final PreparedStatement finalPs = ps;
ret = cm.toStream(rs, componentType).onClose(() -> tryClose(finalPs));
error = false;
return ret;
} finally {
if (error) {
tryClose(ret);
tryClose(rs);
tryClose(ps);
}
}
}
public <T extends Map<String, V>, V> Stream<Map<String, V>> toStream(String sql, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
boolean error = true;
PreparedStatement ps = null;
ResultSet rs = null;
Stream<Map<String, V>> ret = null;
try {
ps = conn.prepareStatement(sql);
rs = this.toResultSet(ps, bindObjects);
final PreparedStatement finalPs = ps;
ret = cm.toStream(rs, componentType, mapValType).onClose(() -> tryClose(finalPs));
error = false;
return ret;
} finally {
if (error) {
tryClose(ret);
tryClose(rs);
tryClose(ps);
}
}
}
//IFJAVA8_END
// these are standard getters
public ResultSetMapper getCustomResultSetMapper() {
@ -412,10 +459,26 @@ public class QueryMapper implements Closeable {
return cm.toResultSetIterable(bindExecute(ps, bindObjects), componentType);
}
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterableMap(PreparedStatement ps, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return cm.toResultSetIterableMap(bindExecute(ps, bindObjects), componentType, mapValType);
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterable(PreparedStatement ps, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return cm.toResultSetIterable(bindExecute(ps, bindObjects), componentType, mapValType);
}
//IFJAVA8_START
public <T> Stream<T> toStream(PreparedStatement ps, Class<T> componentType, final Object... bindObjects) throws SQLException {
return cm.toStream(bindExecute(ps, bindObjects), componentType);
}
//IFJAVA8_END
//IFJAVA8_START
public <T extends Map<String, V>, V> Stream<Map<String, V>> toStream(PreparedStatement ps, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return cm.toStream(bindExecute(ps, bindObjects), componentType, mapValType);
}
//IFJAVA8_END
public <T extends Map<String, V>, V> Map<String, V> toSingleMap(PreparedStatement ps, Class<T> componentType, Class<V> mapValType, final Object... bindObjects) throws SQLException {
return cm.toSingleMap(bindExecute(ps, bindObjects), componentType, mapValType);
}

View File

@ -29,6 +29,9 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.*;
//IFJAVA8_START
import java.util.stream.Stream;
//IFJAVA8_END
/**
* Default ResultSetMapper implementation for Objects.
@ -141,6 +144,20 @@ public class ResultSetMapper implements RowMapperProvider {
}
}
//IFJAVA8_START
protected <T> Stream<T> privToStream(ResultSet rs, Class<T> componentType, Calendar cal, Class<?> mapValType) {
try {
return ResultSetIterable.getStream(rs,
rs.next() ? getRowMapper(rs, componentType, cal, mapValType, null).getResultSetToObject() : null,
cal);
} catch (SQLException e) {
throw new MapperException("cannot create Stream", e);
}
}
//IFJAVA8_END
protected <T extends Collection<E>, E> T privToCollection(ResultSet rs, final Class<T> collectionType, Class<E> componentType, int arrayMaxLength, Calendar cal, Class<?> mapValType) {
return privToCollection(rs, instantiateClass(collectionType, ArrayList.class), componentType, arrayMaxLength, cal, mapValType);
}
@ -455,10 +472,23 @@ public class ResultSetMapper implements RowMapperProvider {
}
@SuppressWarnings("unchecked")
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterableMap(ResultSet rs, Class<T> componentType, Class<V> mapValType, Calendar cal) {
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterable(ResultSet rs, Class<T> componentType, Class<V> mapValType, Calendar cal) {
return (ResultSetIterable<Map<String, V>>)privToResultSetIterable(rs, componentType, cal, mapValType);
}
//IFJAVA8_START
public <T> Stream<T> toStream(ResultSet rs, Class<T> componentType, Calendar cal) {
return privToStream(rs, componentType, cal, null);
}
@SuppressWarnings("unchecked")
public <T extends Map<String, V>, V> Stream<Map<String, V>> toStream(ResultSet rs, Class<T> componentType, Class<V> mapValType, Calendar cal) {
return (Stream<Map<String, V>>)privToStream(rs, componentType, cal, mapValType);
}
//IFJAVA8_END
public <T extends Collection<E>, E> T toCollection(ResultSet rs, final Class<T> collectionType, Class<E> componentType, int arrayMaxLength, Calendar cal) {
return privToCollection(rs, collectionType, componentType, arrayMaxLength, cal, null);
}
@ -633,10 +663,26 @@ public class ResultSetMapper implements RowMapperProvider {
return this.toResultSetIterable(rs, componentType, cal);
}
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterableMap(ResultSet rs, Class<T> componentType, Class<V> mapValType) {
return this.toResultSetIterableMap(rs, componentType, mapValType, cal);
public <T extends Map<String, V>, V> ResultSetIterable<Map<String, V>> toResultSetIterable(ResultSet rs, Class<T> componentType, Class<V> mapValType) {
return this.toResultSetIterable(rs, componentType, mapValType, cal);
}
//IFJAVA8_START
public <T> Stream<T> toStream(ResultSet rs, Class<T> componentType) {
return this.toStream(rs, componentType, cal);
}
//IFJAVA8_END
//IFJAVA8_START
public <T extends Map<String, V>, V> Stream<Map<String, V>> toStream(ResultSet rs, Class<T> componentType, Class<V> mapValType) {
return this.toStream(rs, componentType, mapValType, cal);
}
//IFJAVA8_END
public <T extends Map<String, V>, V> Map<String, V> toSingleMap(ResultSet rs, Class<T> componentType, Class<V> mapValType) {
return this.toSingleMap(rs, componentType, mapValType, cal);
}

View File

@ -10,6 +10,10 @@ import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;
//IFJAVA8_START
import java.util.stream.Collectors;
import java.util.stream.Stream;
//IFJAVA8_END
import static com.moparisthebest.jdbc.TryClose.tryClose;
import static org.junit.Assert.assertArrayEquals;
@ -406,4 +410,19 @@ public class QueryMapperTest {
rsi.close();
assertArrayEquals(people, fromDb.toArray());
}
//IFJAVA8_START
@Test
public void testStream() throws SQLException {
final List<FieldPerson> fromDb;
try(Stream<FieldPerson> rsi = qm.toStream("SELECT * from person WHERE person_no IN (?,?,?) ORDER BY person_no",
FieldPerson.class, people[0].getPersonNo(), people[1].getPersonNo(), people[2].getPersonNo())) {
fromDb = rsi.collect(Collectors.toList());
}
assertArrayEquals(people, fromDb.toArray());
}
//IFJAVA8_END
}