diff --git a/common/pom.xml b/common/pom.xml index 698710d..1cf10fa 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -24,4 +24,20 @@ ${project.artifactId} + + + jdk16 + + [1.6,1.8) + + + + + com.google.code.maven-replacer-plugin + replacer + + + + + diff --git a/common/src/main/java/com/moparisthebest/jdbc/TryClose.java b/common/src/main/java/com/moparisthebest/jdbc/TryClose.java index d401dc4..3470745 100644 --- a/common/src/main/java/com/moparisthebest/jdbc/TryClose.java +++ b/common/src/main/java/com/moparisthebest/jdbc/TryClose.java @@ -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 } diff --git a/common/src/main/java/com/moparisthebest/jdbc/util/ResultSetIterable.java b/common/src/main/java/com/moparisthebest/jdbc/util/ResultSetIterable.java index 99d0a4b..9be78e1 100644 --- a/common/src/main/java/com/moparisthebest/jdbc/util/ResultSetIterable.java +++ b/common/src/main/java/com/moparisthebest/jdbc/util/ResultSetIterable.java @@ -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 implements Iterable, Iterator, Closeable * ResultSetIterable rsi = ResultSetIterable.getResultSetIterable(rs, rs.next() ? complicatedBuildResultSetToObject(rs) : null, cal); *

* 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 *

* This assumes rs.next() was called once before sent into this function */ @SuppressWarnings("unchecked") public static ResultSetIterable getResultSetIterable(final ResultSet rs, final ResultSetToObject rsto, final Calendar cal) { - if (rsto == null) + if (rsto == null) { + tryClose(rs); // have to do this here... return (ResultSetIterable) EMPTY_RESULT_SET_ITERABLE; + } final ResultSetIterable ret = new ResultSetIterable(rs, rsto, cal); ret.calledNext = true; return ret; } + /** + * This is a convenience method meant to be called like this, where rs is a ResultSet + *

+ * Stream rsi = ResultSetIterable.getStream(rs, rs.next() ? complicatedBuildResultSetToObject(rs) : null, cal); + *

+ * 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 + *

+ * The stream returned MUST be closed in a try-with-resources or finally because the ResultSet is held open until then + *

+ * This assumes rs.next() was called once before sent into this function + */ + //IFJAVA8_START + @SuppressWarnings("unchecked") + public static Stream getStream(final ResultSet rs, final ResultSetToObject rsto, final Calendar cal) { + final Stream ret; + if (rsto == null) { + // todo: static object for this? don't forget to close resultset if so + return (Stream) StreamSupport.stream(Spliterators.emptySpliterator(), false); + } else { + final ResultSetIterable rsi = new ResultSetIterable(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 rsto; diff --git a/pom.xml b/pom.xml index 36e211a..36e851d 100644 --- a/pom.xml +++ b/pom.xml @@ -203,6 +203,7 @@ */src/main/java/**/* + */src/test/java/**/* target/** diff --git a/querymapper/genQueryMapper.sh b/querymapper/genQueryMapper.sh index 8058312..39de0ee 100755 --- a/querymapper/genQueryMapper.sh +++ b/querymapper/genQueryMapper.sh @@ -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" <> "$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" <> "$query" <> "$caching_query" </dev/null + done finishFile "src/main/java/com/moparisthebest/jdbc/QueryMapper.java" diff --git a/querymapper/pom.xml b/querymapper/pom.xml index ace85e0..00505fe 100644 --- a/querymapper/pom.xml +++ b/querymapper/pom.xml @@ -50,4 +50,20 @@ + + + jdk16 + + [1.6,1.8) + + + + + com.google.code.maven-replacer-plugin + replacer + + + + + diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/CachingQueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/CachingQueryMapper.java index 8c71e56..0251991 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/CachingQueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/CachingQueryMapper.java @@ -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 , V> ResultSetIterable> toResultSetIterableMap(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { - return super.toResultSetIterableMap(getPreparedStatement(sql), componentType, mapValType, bindObjects); + public , V> ResultSetIterable> toResultSetIterable(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + return super.toResultSetIterable(getPreparedStatement(sql), componentType, mapValType, bindObjects); } + //IFJAVA8_START + + @Override + public Stream toStream(String sql, Class componentType, final Object... bindObjects) throws SQLException { + return super.toStream(getPreparedStatement(sql), componentType, bindObjects); + } + + //IFJAVA8_END + + //IFJAVA8_START + + @Override + public , V> Stream> toStream(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + return super.toStream(getPreparedStatement(sql), componentType, mapValType, bindObjects); + } + + //IFJAVA8_END + @Override public , V> Map toSingleMap(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toSingleMap(getPreparedStatement(sql), componentType, mapValType, bindObjects); diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java index 1447a76..3c490a8 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java @@ -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 , V> ResultSetIterable> toResultSetIterableMap(PreparedStatement ps, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { - return delegate.toResultSetIterableMap(ps, componentType, mapValType, bindObjects); + public , V> ResultSetIterable> toResultSetIterable(PreparedStatement ps, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + return delegate.toResultSetIterable(ps, componentType, mapValType, bindObjects); } @Override - public , V> ResultSetIterable> toResultSetIterableMap(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { - return delegate.toResultSetIterableMap(prepareSql(sql, bindObjects), componentType, mapValType, bindObjects); + public , V> ResultSetIterable> toResultSetIterable(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + return delegate.toResultSetIterable(prepareSql(sql, bindObjects), componentType, mapValType, bindObjects); } + //IFJAVA8_START + + @Override + public Stream toStream(PreparedStatement ps, Class componentType, final Object... bindObjects) throws SQLException { + return delegate.toStream(ps, componentType, bindObjects); + } + + @Override + public Stream toStream(String sql, Class componentType, final Object... bindObjects) throws SQLException { + return delegate.toStream(prepareSql(sql, bindObjects), componentType, bindObjects); + } + + //IFJAVA8_END + + //IFJAVA8_START + + @Override + public , V> Stream> toStream(PreparedStatement ps, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + return delegate.toStream(ps, componentType, mapValType, bindObjects); + } + + @Override + public , V> Stream> toStream(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + return delegate.toStream(prepareSql(sql, bindObjects), componentType, mapValType, bindObjects); + } + + //IFJAVA8_END + @Override public , V> Map toSingleMap(PreparedStatement ps, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return delegate.toSingleMap(ps, componentType, mapValType, bindObjects); diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/NullQueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/NullQueryMapper.java index 17b157a..87472de 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/NullQueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/NullQueryMapper.java @@ -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 , V> ResultSetIterable> toResultSetIterableMap(PreparedStatement query, Class componentType, Class mapValType, final Object... bindObjects) { + public , V> ResultSetIterable> toResultSetIterable(PreparedStatement query, Class componentType, Class 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 , V> ResultSetIterable> toResultSetIterableMap(String query, Class componentType, Class mapValType, final Object... bindObjects) { + public , V> ResultSetIterable> toResultSetIterable(String query, Class componentType, Class 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 Stream toStream(PreparedStatement query, Class componentType, final Object... bindObjects) { + try { + return delegate.toStream(query, componentType, bindObjects); + } catch (Throwable e) { + if (verbose) e.printStackTrace(); + } + return null; + } + + @Override + public Stream toStream(String query, Class 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 , V> Stream> toStream(PreparedStatement query, Class componentType, Class mapValType, final Object... bindObjects) { + try { + return delegate.toStream(query, componentType, mapValType, bindObjects); + } catch (Throwable e) { + if (verbose) e.printStackTrace(); + } + return null; + } + + @Override + public , V> Stream> toStream(String query, Class componentType, Class 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 , V> Map toSingleMap(PreparedStatement query, Class componentType, Class mapValType, final Object... bindObjects) { try { diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java index 94f6b5e..413e23a 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java @@ -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 , V> ResultSetIterable> toResultSetIterableMap(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + public , V> ResultSetIterable> toResultSetIterable(String sql, Class componentType, Class 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 Stream toStream(String sql, Class componentType, final Object... bindObjects) throws SQLException { + boolean error = true; + PreparedStatement ps = null; + ResultSet rs = null; + Stream 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 , V> Stream> toStream(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + boolean error = true; + PreparedStatement ps = null; + ResultSet rs = null; + Stream> 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 , V> ResultSetIterable> toResultSetIterableMap(PreparedStatement ps, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { - return cm.toResultSetIterableMap(bindExecute(ps, bindObjects), componentType, mapValType); + public , V> ResultSetIterable> toResultSetIterable(PreparedStatement ps, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + return cm.toResultSetIterable(bindExecute(ps, bindObjects), componentType, mapValType); } + //IFJAVA8_START + + public Stream toStream(PreparedStatement ps, Class componentType, final Object... bindObjects) throws SQLException { + return cm.toStream(bindExecute(ps, bindObjects), componentType); + } + + //IFJAVA8_END + + //IFJAVA8_START + + public , V> Stream> toStream(PreparedStatement ps, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { + return cm.toStream(bindExecute(ps, bindObjects), componentType, mapValType); + } + + //IFJAVA8_END + public , V> Map toSingleMap(PreparedStatement ps, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return cm.toSingleMap(bindExecute(ps, bindObjects), componentType, mapValType); } diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/ResultSetMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/ResultSetMapper.java index d1a1224..d31122e 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/ResultSetMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/ResultSetMapper.java @@ -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 Stream privToStream(ResultSet rs, Class 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 , E> T privToCollection(ResultSet rs, final Class collectionType, Class 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 , V> ResultSetIterable> toResultSetIterableMap(ResultSet rs, Class componentType, Class mapValType, Calendar cal) { + public , V> ResultSetIterable> toResultSetIterable(ResultSet rs, Class componentType, Class mapValType, Calendar cal) { return (ResultSetIterable>)privToResultSetIterable(rs, componentType, cal, mapValType); } + //IFJAVA8_START + + public Stream toStream(ResultSet rs, Class componentType, Calendar cal) { + return privToStream(rs, componentType, cal, null); + } + + @SuppressWarnings("unchecked") + public , V> Stream> toStream(ResultSet rs, Class componentType, Class mapValType, Calendar cal) { + return (Stream>)privToStream(rs, componentType, cal, mapValType); + } + + //IFJAVA8_END + public , E> T toCollection(ResultSet rs, final Class collectionType, Class 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 , V> ResultSetIterable> toResultSetIterableMap(ResultSet rs, Class componentType, Class mapValType) { - return this.toResultSetIterableMap(rs, componentType, mapValType, cal); + public , V> ResultSetIterable> toResultSetIterable(ResultSet rs, Class componentType, Class mapValType) { + return this.toResultSetIterable(rs, componentType, mapValType, cal); } + //IFJAVA8_START + + public Stream toStream(ResultSet rs, Class componentType) { + return this.toStream(rs, componentType, cal); + } + + //IFJAVA8_END + + //IFJAVA8_START + + public , V> Stream> toStream(ResultSet rs, Class componentType, Class mapValType) { + return this.toStream(rs, componentType, mapValType, cal); + } + + //IFJAVA8_END + public , V> Map toSingleMap(ResultSet rs, Class componentType, Class mapValType) { return this.toSingleMap(rs, componentType, mapValType, cal); } diff --git a/querymapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java b/querymapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java index f5f52bc..fba9ade 100644 --- a/querymapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java +++ b/querymapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java @@ -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 fromDb; + try(Stream 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 }