From 4f5ae22a52b1d8abbd11c05eac50876eb8264026 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 8 Nov 2018 13:43:07 +0100 Subject: [PATCH] Consistently return empty array in case of empty batch arguments Issue: SPR-17476 (cherry picked from commit 362c59c3102acb68145cf1689b6391cb1fb94486) --- .../jdbc/core/BatchUpdateUtils.java | 13 +- .../NamedParameterBatchUpdateUtils.java | 11 +- .../jdbc/core/JdbcTemplateTests.java | 258 ++++++------------ .../NamedParameterJdbcTemplateTests.java | 206 +++++++------- 4 files changed, 191 insertions(+), 297 deletions(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/BatchUpdateUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/BatchUpdateUtils.java index d18099a649..d1546a9d3e 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/BatchUpdateUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/BatchUpdateUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,24 +25,29 @@ import java.util.List; * Mainly for internal use within the framework. * * @author Thomas Risberg + * @author Juergen Hoeller * @since 3.0 */ public abstract class BatchUpdateUtils { public static int[] executeBatchUpdate( - String sql, final List batchValues, final int[] columnTypes, JdbcOperations jdbcOperations) { + String sql, final List batchArgs, final int[] columnTypes, JdbcOperations jdbcOperations) { + + if (batchArgs.isEmpty()) { + return new int[0]; + } return jdbcOperations.batchUpdate( sql, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { - Object[] values = batchValues.get(i); + Object[] values = batchArgs.get(i); setStatementParameters(values, ps, columnTypes); } @Override public int getBatchSize() { - return batchValues.size(); + return batchArgs.size(); } }); } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterBatchUpdateUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterBatchUpdateUtils.java index cffc7a850e..4430e05b64 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterBatchUpdateUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterBatchUpdateUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,15 +28,16 @@ import org.springframework.jdbc.core.JdbcOperations; * Mainly for internal use within the framework. * * @author Thomas Risberg + * @author Juergen Hoeller * @since 3.0 */ public class NamedParameterBatchUpdateUtils extends BatchUpdateUtils { - public static int[] executeBatchUpdateWithNamedParameters(final ParsedSql parsedSql, - final SqlParameterSource[] batchArgs, JdbcOperations jdbcOperations) { + public static int[] executeBatchUpdateWithNamedParameters( + final ParsedSql parsedSql, final SqlParameterSource[] batchArgs, JdbcOperations jdbcOperations) { - if (batchArgs.length <= 0) { - return new int[] {0}; + if (batchArgs.length == 0) { + return new int[0]; } String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, batchArgs[0]); diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java index 4e8b2cea34..73080c16e8 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java @@ -28,6 +28,7 @@ import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -152,76 +153,46 @@ public class JdbcTemplateTests { @Test public void testStringsWithStaticSql() throws Exception { - doTestStrings(null, null, null, null, new JdbcTemplateCallback() { - @Override - public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { - template.query(sql, rch); - } - }); + doTestStrings(null, null, null, null, (template, sql, rch) -> template.query(sql, rch)); } @Test public void testStringsWithStaticSqlAndFetchSizeAndMaxRows() throws Exception { - doTestStrings(10, 20, 30, null, new JdbcTemplateCallback() { - @Override - public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { - template.query(sql, rch); - } - }); + doTestStrings(10, 20, 30, null, (template, sql, rch) -> template.query(sql, rch)); } @Test public void testStringsWithEmptyPreparedStatementSetter() throws Exception { - doTestStrings(null, null, null, null, new JdbcTemplateCallback() { - @Override - public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { - template.query(sql, (PreparedStatementSetter) null, rch); - } - }); + doTestStrings(null, null, null, null, (template, sql, rch) -> + template.query(sql, (PreparedStatementSetter) null, rch)); } @Test public void testStringsWithPreparedStatementSetter() throws Exception { final Integer argument = 99; - doTestStrings(null, null, null, argument, new JdbcTemplateCallback() { - @Override - public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { - template.query(sql, new PreparedStatementSetter() { - @Override - public void setValues(PreparedStatement ps) throws SQLException { - ps.setObject(1, argument); - } - }, rch); - } - }); + doTestStrings(null, null, null, argument, (template, sql, rch) -> template.query(sql, ps -> { + ps.setObject(1, argument); + }, rch)); } @Test public void testStringsWithEmptyPreparedStatementArgs() throws Exception { - doTestStrings(null, null, null, null, new JdbcTemplateCallback() { - @Override - public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { - template.query(sql, (Object[]) null, rch); - } - }); + doTestStrings(null, null, null, null, + (template, sql, rch) -> template.query(sql, (Object[]) null, rch)); } @Test public void testStringsWithPreparedStatementArgs() throws Exception { final Integer argument = 99; - doTestStrings(null, null, null, argument, new JdbcTemplateCallback() { - @Override - public void doInJdbcTemplate(JdbcTemplate template, String sql, RowCallbackHandler rch) { - template.query(sql, new Object[] { argument }, rch); - } - }); + doTestStrings(null, null, null, argument, + (template, sql, rch) -> template.query(sql, new Object[] {argument}, rch)); } private void doTestStrings(Integer fetchSize, Integer maxRows, Integer queryTimeout, Object argument, JdbcTemplateCallback jdbcTemplateCallback) throws Exception { String sql = "SELECT FORENAME FROM CUSTMR"; - String[] results = { "rod", "gary", " portia" }; + String[] results = {"rod", "gary", " portia"}; class StringHandler implements RowCallbackHandler { private List list = new LinkedList<>(); @@ -357,11 +328,8 @@ public class JdbcTemplateTests { this.thrown.expect(sameInstance(runtimeException)); try { - this.template.query(sql, new RowCallbackHandler() { - @Override - public void processRow(ResultSet rs) { - throw runtimeException; - } + this.template.query(sql, (RowCallbackHandler) rs -> { + throw runtimeException; }); } finally { @@ -398,10 +366,10 @@ public class JdbcTemplateTests { given(this.preparedStatement.executeUpdate()).willReturn(rowsAffected); int actualRowsAffected = this.template.update(sql, - new Object[] {4, new SqlParameterValue(Types.NUMERIC, 2, new Float(1.4142))}); + 4, new SqlParameterValue(Types.NUMERIC, 2, Float.valueOf(1.4142f))); assertTrue("Actual rows affected is correct", actualRowsAffected == rowsAffected); verify(this.preparedStatement).setObject(1, 4); - verify(this.preparedStatement).setObject(2, new Float(1.4142), Types.NUMERIC, 2); + verify(this.preparedStatement).setObject(2, Float.valueOf(1.4142f), Types.NUMERIC, 2); verify(this.preparedStatement).close(); verify(this.connection).close(); } @@ -463,8 +431,7 @@ public class JdbcTemplateTests { public void testBatchUpdateWithBatchFailure() throws Exception { final String[] sql = {"A", "B", "C", "D"}; given(this.statement.executeBatch()).willThrow( - new BatchUpdateException(new int[] { 1, Statement.EXECUTE_FAILED, 1, - Statement.EXECUTE_FAILED })); + new BatchUpdateException(new int[] {1, Statement.EXECUTE_FAILED, 1, Statement.EXECUTE_FAILED})); mockDatabaseMetaData(true); given(this.connection.createStatement()).willReturn(this.statement); @@ -525,17 +492,15 @@ public class JdbcTemplateTests { @Test public void testBatchUpdateWithPreparedStatement() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final int[] ids = new int[] { 100, 200 }; - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] ids = new int[] {100, 200}; + final int[] rowsAffected = new int[] {1, 2}; given(this.preparedStatement.executeBatch()).willReturn(rowsAffected); mockDatabaseMetaData(true); - BatchPreparedStatementSetter setter = - new BatchPreparedStatementSetter() { + BatchPreparedStatementSetter setter = new BatchPreparedStatementSetter() { @Override - public void setValues(PreparedStatement ps, int i) - throws SQLException { + public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setInt(1, ids[i]); } @Override @@ -561,8 +526,8 @@ public class JdbcTemplateTests { @Test public void testInterruptibleBatchUpdate() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final int[] ids = new int[] { 100, 200 }; - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] ids = new int[] {100, 200}; + final int[] rowsAffected = new int[] {1, 2}; given(this.preparedStatement.executeBatch()).willReturn(rowsAffected); mockDatabaseMetaData(true); @@ -602,8 +567,8 @@ public class JdbcTemplateTests { @Test public void testInterruptibleBatchUpdateWithBaseClass() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final int[] ids = new int[] { 100, 200 }; - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] ids = new int[] {100, 200}; + final int[] rowsAffected = new int[] {1, 2}; given(this.preparedStatement.executeBatch()).willReturn(rowsAffected); mockDatabaseMetaData(true); @@ -639,8 +604,8 @@ public class JdbcTemplateTests { @Test public void testInterruptibleBatchUpdateWithBaseClassAndNoBatchSupport() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final int[] ids = new int[] { 100, 200 }; - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] ids = new int[] {100, 200}; + final int[] rowsAffected = new int[] {1, 2}; given(this.preparedStatement.executeUpdate()).willReturn(rowsAffected[0], rowsAffected[1]); mockDatabaseMetaData(false); @@ -676,8 +641,8 @@ public class JdbcTemplateTests { @Test public void testBatchUpdateWithPreparedStatementAndNoBatchSupport() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final int[] ids = new int[] { 100, 200 }; - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] ids = new int[] {100, 200}; + final int[] rowsAffected = new int[] {1, 2}; given(this.preparedStatement.executeUpdate()).willReturn(rowsAffected[0], rowsAffected[1]); @@ -707,7 +672,7 @@ public class JdbcTemplateTests { @Test public void testBatchUpdateFails() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final int[] ids = new int[] { 100, 200 }; + final int[] ids = new int[] {100, 200}; SQLException sqlException = new SQLException(); given(this.preparedStatement.executeBatch()).willThrow(sqlException); @@ -738,21 +703,28 @@ public class JdbcTemplateTests { } } + @Test + public void testBatchUpdateWithEmptyList() throws Exception { + final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; + JdbcTemplate template = new JdbcTemplate(this.dataSource, false); + + int[] actualRowsAffected = template.batchUpdate(sql, Collections.emptyList()); + assertTrue("executed 0 updates", actualRowsAffected.length == 0); + } + @Test public void testBatchUpdateWithListOfObjectArrays() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final List ids = new ArrayList<>(); + final List ids = new ArrayList<>(2); ids.add(new Object[] {100}); ids.add(new Object[] {200}); - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] rowsAffected = new int[] {1, 2}; given(this.preparedStatement.executeBatch()).willReturn(rowsAffected); mockDatabaseMetaData(true); - JdbcTemplate template = new JdbcTemplate(this.dataSource, false); int[] actualRowsAffected = template.batchUpdate(sql, ids); - assertTrue("executed 2 updates", actualRowsAffected.length == 2); assertEquals(rowsAffected[0], actualRowsAffected[0]); assertEquals(rowsAffected[1], actualRowsAffected[1]); @@ -767,18 +739,17 @@ public class JdbcTemplateTests { @Test public void testBatchUpdateWithListOfObjectArraysPlusTypeInfo() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final List ids = new ArrayList<>(); + final List ids = new ArrayList<>(2); ids.add(new Object[] {100}); ids.add(new Object[] {200}); final int[] sqlTypes = new int[] {Types.NUMERIC}; - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] rowsAffected = new int[] {1, 2}; given(this.preparedStatement.executeBatch()).willReturn(rowsAffected); mockDatabaseMetaData(true); - this.template = new JdbcTemplate(this.dataSource, false); - int[] actualRowsAffected = this.template.batchUpdate(sql, ids, sqlTypes); + int[] actualRowsAffected = this.template.batchUpdate(sql, ids, sqlTypes); assertTrue("executed 2 updates", actualRowsAffected.length == 2); assertEquals(rowsAffected[0], actualRowsAffected[0]); assertEquals(rowsAffected[1], actualRowsAffected[1]); @@ -793,23 +764,17 @@ public class JdbcTemplateTests { public void testBatchUpdateWithCollectionOfObjects() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; final List ids = Arrays.asList(100, 200, 300); - final int[] rowsAffected1 = new int[] { 1, 2 }; - final int[] rowsAffected2 = new int[] { 3 }; + final int[] rowsAffected1 = new int[] {1, 2}; + final int[] rowsAffected2 = new int[] {3}; given(this.preparedStatement.executeBatch()).willReturn(rowsAffected1, rowsAffected2); mockDatabaseMetaData(true); - ParameterizedPreparedStatementSetter setter = new ParameterizedPreparedStatementSetter() { - @Override - public void setValues(PreparedStatement ps, Integer argument) throws SQLException { - ps.setInt(1, argument.intValue()); - } - }; - + ParameterizedPreparedStatementSetter setter = (ps, argument) -> ps.setInt(1, argument.intValue()); JdbcTemplate template = new JdbcTemplate(this.dataSource, false); int[][] actualRowsAffected = template.batchUpdate(sql, ids, 2, setter); - assertTrue("executed 2 updates", actualRowsAffected[0].length == 2); + assertEquals("executed 2 updates", 2, actualRowsAffected[0].length); assertEquals(rowsAffected1[0], actualRowsAffected[0][0]); assertEquals(rowsAffected1[1], actualRowsAffected[0][1]); assertEquals(rowsAffected2[0], actualRowsAffected[1][0]); @@ -823,19 +788,20 @@ public class JdbcTemplateTests { } @Test - public void testCouldntGetConnectionForOperationOrExceptionTranslator() throws SQLException { + public void testCouldNotGetConnectionForOperationOrExceptionTranslator() throws SQLException { SQLException sqlException = new SQLException("foo", "07xxx"); this.dataSource = mock(DataSource.class); given(this.dataSource.getConnection()).willThrow(sqlException); JdbcTemplate template = new JdbcTemplate(this.dataSource, false); RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + this.thrown.expect(CannotGetJdbcConnectionException.class); this.thrown.expect(exceptionCause(sameInstance(sqlException))); template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch); } @Test - public void testCouldntGetConnectionForOperationWithLazyExceptionTranslator() throws SQLException { + public void testCouldNotGetConnectionForOperationWithLazyExceptionTranslator() throws SQLException { SQLException sqlException = new SQLException("foo", "07xxx"); this.dataSource = mock(DataSource.class); given(this.dataSource.getConnection()).willThrow(sqlException); @@ -843,30 +809,31 @@ public class JdbcTemplateTests { this.template.setDataSource(this.dataSource); this.template.afterPropertiesSet(); RowCountCallbackHandler rcch = new RowCountCallbackHandler(); + this.thrown.expect(CannotGetJdbcConnectionException.class); this.thrown.expect(exceptionCause(sameInstance(sqlException))); this.template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch); } @Test - public void testCouldntGetConnectionInOperationWithExceptionTranslatorInitializedViaBeanProperty() + public void testCouldNotGetConnectionInOperationWithExceptionTranslatorInitializedViaBeanProperty() throws SQLException { - doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(true); + doTestCouldNotGetConnectionInOperationWithExceptionTranslatorInitialized(true); } @Test - public void testCouldntGetConnectionInOperationWithExceptionTranslatorInitializedInAfterPropertiesSet() + public void testCouldNotGetConnectionInOperationWithExceptionTranslatorInitializedInAfterPropertiesSet() throws SQLException { - doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(false); + doTestCouldNotGetConnectionInOperationWithExceptionTranslatorInitialized(false); } /** * If beanProperty is true, initialize via exception translator bean property; * if false, use afterPropertiesSet(). */ - private void doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(boolean beanProperty) + private void doTestCouldNotGetConnectionInOperationWithExceptionTranslatorInitialized(boolean beanProperty) throws SQLException { SQLException sqlException = new SQLException("foo", "07xxx"); @@ -897,14 +864,9 @@ public class JdbcTemplateTests { given(this.preparedStatement.executeUpdate()).willReturn(expectedRowsUpdated); - PreparedStatementSetter pss = new PreparedStatementSetter() { - @Override - public void setValues(PreparedStatement ps) throws SQLException { - ps.setString(1, name); - } - }; + PreparedStatementSetter pss = ps -> ps.setString(1, name); int actualRowsUpdated = new JdbcTemplate(this.dataSource).update(sql, pss); - assertTrue("updated correct # of rows", actualRowsUpdated == expectedRowsUpdated); + assertEquals("updated correct # of rows", actualRowsUpdated, expectedRowsUpdated); verify(this.preparedStatement).setString(1, name); verify(this.preparedStatement).close(); verify(this.connection).close(); @@ -917,12 +879,7 @@ public class JdbcTemplateTests { SQLException sqlException = new SQLException(); given(this.preparedStatement.executeUpdate()).willThrow(sqlException); - PreparedStatementSetter pss = new PreparedStatementSetter() { - @Override - public void setValues(PreparedStatement ps) throws SQLException { - ps.setString(1, name); - } - }; + PreparedStatementSetter pss = ps -> ps.setString(1, name); this.thrown.expect(DataAccessException.class); this.thrown.expect(exceptionCause(sameInstance(sqlException))); try { @@ -936,7 +893,7 @@ public class JdbcTemplateTests { } @Test - public void testCouldntClose() throws Exception { + public void testCouldNotClose() throws Exception { SQLException sqlException = new SQLException("bar"); given(this.connection.createStatement()).willReturn(this.statement); given(this.resultSet.next()).willReturn(false); @@ -966,11 +923,8 @@ public class JdbcTemplateTests { this.thrown.expect(SQLWarningException.class); this.thrown.expect(exceptionCause(sameInstance(warnings))); try { - t.query(sql, new RowCallbackHandler() { - @Override - public void processRow(ResultSet rs) throws SQLException { - rs.getByte(1); - } + t.query(sql, rs -> { + rs.getByte(1); }); } finally { @@ -992,11 +946,8 @@ public class JdbcTemplateTests { // Too long: truncation this.template.setIgnoreWarnings(true); - this.template.query(sql, new RowCallbackHandler() { - @Override - public void processRow(ResultSet rs) throws java.sql.SQLException { - rs.getByte(1); - } + this.template.query(sql, rs -> { + rs.getByte(1); }); verify(this.resultSet).close(); @@ -1016,11 +967,8 @@ public class JdbcTemplateTests { this.thrown.expect(BadSqlGrammarException.class); this.thrown.expect(exceptionCause(sameInstance(sqlException))); try { - this.template.query(sql, new RowCallbackHandler() { - @Override - public void processRow(ResultSet rs) throws SQLException { - throw sqlException; - } + this.template.query(sql, (RowCallbackHandler) rs -> { + throw sqlException; }); fail("Should have thrown BadSqlGrammarException"); } @@ -1047,11 +995,8 @@ public class JdbcTemplateTests { this.thrown.expect(BadSqlGrammarException.class); this.thrown.expect(exceptionCause(sameInstance(sqlException))); try { - template.query(sql, new RowCallbackHandler() { - @Override - public void processRow(ResultSet rs) throws SQLException { - throw sqlException; - } + template.query(sql, (RowCallbackHandler) rs -> { + throw sqlException; }); } finally { @@ -1084,11 +1029,8 @@ public class JdbcTemplateTests { this.thrown.expect(BadSqlGrammarException.class); this.thrown.expect(exceptionCause(sameInstance(sqlException))); try { - template.query(sql, new RowCallbackHandler() { - @Override - public void processRow(ResultSet rs) throws SQLException { - throw sqlException; - } + template.query(sql, (RowCallbackHandler) rs -> { + throw sqlException; }); } finally { @@ -1204,34 +1146,22 @@ public class JdbcTemplateTests { given(this.connection.createStatement()).willReturn(this.statement); try { - this.template.query("my query", new ResultSetExtractor() { - @Override - public Object extractData(ResultSet rs) { - throw new InvalidDataAccessApiUsageException(""); - } + this.template.query("my query", (ResultSetExtractor) rs -> { + throw new InvalidDataAccessApiUsageException(""); }); fail("Should have thrown InvalidDataAccessApiUsageException"); } - catch (InvalidDataAccessApiUsageException idaauex) { + catch (InvalidDataAccessApiUsageException ex) { // ok } try { - this.template.query(new PreparedStatementCreator() { - @Override - public PreparedStatement createPreparedStatement(Connection con) - throws SQLException { - return con.prepareStatement("my query"); - } - }, new ResultSetExtractor() { - @Override - public Object extractData(ResultSet rs2) { - throw new InvalidDataAccessApiUsageException(""); - } + this.template.query(con -> con.prepareStatement("my query"), (ResultSetExtractor) rs2 -> { + throw new InvalidDataAccessApiUsageException(""); }); fail("Should have thrown InvalidDataAccessApiUsageException"); } - catch (InvalidDataAccessApiUsageException idaauex) { + catch (InvalidDataAccessApiUsageException ex) { // ok } @@ -1247,24 +1177,13 @@ public class JdbcTemplateTests { given(this.callableStatement.execute()).willReturn(true); given(this.callableStatement.getUpdateCount()).willReturn(-1); - List params = new ArrayList<>(); - params.add(new SqlReturnResultSet("", new RowCallbackHandler() { - @Override - public void processRow(ResultSet rs) { - throw new InvalidDataAccessApiUsageException(""); - } - - })); + SqlParameter param = new SqlReturnResultSet("", (RowCallbackHandler) rs -> { + throw new InvalidDataAccessApiUsageException(""); + }); this.thrown.expect(InvalidDataAccessApiUsageException.class); try { - this.template.call(new CallableStatementCreator() { - @Override - public CallableStatement createCallableStatement(Connection conn) - throws SQLException { - return conn.prepareCall("my query"); - } - }, params); + this.template.call(conn -> conn.prepareCall("my query"), Collections.singletonList(param)); } finally { verify(this.resultSet).close(); @@ -1275,7 +1194,6 @@ public class JdbcTemplateTests { @Test public void testCaseInsensitiveResultsMap() throws Exception { - given(this.callableStatement.execute()).willReturn(false); given(this.callableStatement.getUpdateCount()).willReturn(-1); given(this.callableStatement.getObject(1)).willReturn("X"); @@ -1287,16 +1205,8 @@ public class JdbcTemplateTests { assertTrue("now it should have been set to case insensitive", this.template.isResultsMapCaseInsensitive()); - List params = new ArrayList<>(); - params.add(new SqlOutParameter("a", 12)); - - Map out = this.template.call(new CallableStatementCreator() { - @Override - public CallableStatement createCallableStatement(Connection conn) - throws SQLException { - return conn.prepareCall("my query"); - } - }, params); + Map out = this.template.call( + conn -> conn.prepareCall("my query"), Collections.singletonList(new SqlOutParameter("a", 12))); assertThat(out, instanceOf(LinkedCaseInsensitiveMap.class)); assertNotNull("we should have gotten the result with upper case", out.get("A")); diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplateTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplateTests.java index 56a3bbf46d..0b17406c96 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplateTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplateTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,14 +34,10 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.springframework.dao.DataAccessException; import org.springframework.jdbc.Customer; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementCallback; -import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.RowCallbackHandler; -import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.SqlParameterValue; import static org.junit.Assert.*; @@ -55,32 +51,40 @@ import static org.mockito.BDDMockito.*; public class NamedParameterJdbcTemplateTests { private static final String SELECT_NAMED_PARAMETERS = - "select id, forename from custmr where id = :id and country = :country"; + "select id, forename from custmr where id = :id and country = :country"; private static final String SELECT_NAMED_PARAMETERS_PARSED = - "select id, forename from custmr where id = ? and country = ?"; + "select id, forename from custmr where id = ? and country = ?"; private static final String SELECT_NO_PARAMETERS = "select id, forename from custmr"; private static final String UPDATE_NAMED_PARAMETERS = - "update seat_status set booking_id = null where performance_id = :perfId and price_band_id = :priceId"; + "update seat_status set booking_id = null where performance_id = :perfId and price_band_id = :priceId"; private static final String UPDATE_NAMED_PARAMETERS_PARSED = - "update seat_status set booking_id = null where performance_id = ? and price_band_id = ?"; + "update seat_status set booking_id = null where performance_id = ? and price_band_id = ?"; private static final String[] COLUMN_NAMES = new String[] {"id", "forename"}; + @Rule public ExpectedException thrown = ExpectedException.none(); private Connection connection; + private DataSource dataSource; + private PreparedStatement preparedStatement; + private ResultSet resultSet; + private DatabaseMetaData databaseMetaData; - private Map params = new HashMap(); + + private Map params = new HashMap<>(); + private NamedParameterJdbcTemplate namedParameterTemplate; + @Before - public void setUp() throws Exception { + public void setup() throws Exception { connection = mock(Connection.class); dataSource = mock(DataSource.class); preparedStatement = mock(PreparedStatement.class); @@ -95,14 +99,15 @@ public class NamedParameterJdbcTemplateTests { given(databaseMetaData.supportsBatchUpdates()).willReturn(true); } + @Test - public void testNullDataSourceProvidedToCtor() throws Exception { + public void testNullDataSourceProvidedToCtor() { thrown.expect(IllegalArgumentException.class); new NamedParameterJdbcTemplate((DataSource) null); } @Test - public void testNullJdbcTemplateProvidedToCtor() throws Exception { + public void testNullJdbcTemplateProvidedToCtor() { thrown.expect(IllegalArgumentException.class); new NamedParameterJdbcTemplate((JdbcOperations) null); } @@ -114,14 +119,10 @@ public class NamedParameterJdbcTemplateTests { params.put("perfId", 1); params.put("priceId", 1); Object result = namedParameterTemplate.execute(UPDATE_NAMED_PARAMETERS, params, - new PreparedStatementCallback() { - @Override - public Object doInPreparedStatement(PreparedStatement ps) - throws SQLException { - assertEquals(preparedStatement, ps); - ps.executeUpdate(); - return "result"; - } + (PreparedStatementCallback) ps -> { + assertEquals(preparedStatement, ps); + ps.executeUpdate(); + return "result"; }); assertEquals("result", result); @@ -139,14 +140,10 @@ public class NamedParameterJdbcTemplateTests { params.put("perfId", new SqlParameterValue(Types.DECIMAL, 1)); params.put("priceId", new SqlParameterValue(Types.INTEGER, 1)); Object result = namedParameterTemplate.execute(UPDATE_NAMED_PARAMETERS, params, - new PreparedStatementCallback() { - @Override - public Object doInPreparedStatement(PreparedStatement ps) - throws SQLException { - assertEquals(preparedStatement, ps); - ps.executeUpdate(); - return "result"; - } + (PreparedStatementCallback) ps -> { + assertEquals(preparedStatement, ps); + ps.executeUpdate(); + return "result"; }); assertEquals("result", result); @@ -162,14 +159,10 @@ public class NamedParameterJdbcTemplateTests { given(preparedStatement.executeUpdate()).willReturn(1); Object result = namedParameterTemplate.execute(SELECT_NO_PARAMETERS, - new PreparedStatementCallback() { - @Override - public Object doInPreparedStatement(PreparedStatement ps) - throws SQLException { - assertEquals(preparedStatement, ps); - ps.executeQuery(); - return "result"; - } + (PreparedStatementCallback) ps -> { + assertEquals(preparedStatement, ps); + ps.executeQuery(); + return "result"; }); assertEquals("result", result); @@ -187,16 +180,12 @@ public class NamedParameterJdbcTemplateTests { params.put("id", new SqlParameterValue(Types.DECIMAL, 1)); params.put("country", "UK"); Customer cust = namedParameterTemplate.query(SELECT_NAMED_PARAMETERS, params, - new ResultSetExtractor() { - @Override - public Customer extractData(ResultSet rs) throws SQLException, - DataAccessException { - rs.next(); - Customer cust = new Customer(); - cust.setId(rs.getInt(COLUMN_NAMES[0])); - cust.setForename(rs.getString(COLUMN_NAMES[1])); - return cust; - } + rs -> { + rs.next(); + Customer cust1 = new Customer(); + cust1.setId(rs.getInt(COLUMN_NAMES[0])); + cust1.setForename(rs.getString(COLUMN_NAMES[1])); + return cust1; }); assertTrue("Customer id was assigned correctly", cust.getId() == 1); @@ -215,16 +204,12 @@ public class NamedParameterJdbcTemplateTests { given(resultSet.getString("forename")).willReturn("rod"); Customer cust = namedParameterTemplate.query(SELECT_NO_PARAMETERS, - new ResultSetExtractor() { - @Override - public Customer extractData(ResultSet rs) throws SQLException, - DataAccessException { - rs.next(); - Customer cust = new Customer(); - cust.setId(rs.getInt(COLUMN_NAMES[0])); - cust.setForename(rs.getString(COLUMN_NAMES[1])); - return cust; - } + rs -> { + rs.next(); + Customer cust1 = new Customer(); + cust1.setId(rs.getInt(COLUMN_NAMES[0])); + cust1.setForename(rs.getString(COLUMN_NAMES[1])); + return cust1; }); assertTrue("Customer id was assigned correctly", cust.getId() == 1); @@ -242,15 +227,12 @@ public class NamedParameterJdbcTemplateTests { params.put("id", new SqlParameterValue(Types.DECIMAL, 1)); params.put("country", "UK"); - final List customers = new LinkedList(); - namedParameterTemplate.query(SELECT_NAMED_PARAMETERS, params, new RowCallbackHandler() { - @Override - public void processRow(ResultSet rs) throws SQLException { - Customer cust = new Customer(); - cust.setId(rs.getInt(COLUMN_NAMES[0])); - cust.setForename(rs.getString(COLUMN_NAMES[1])); - customers.add(cust); - } + final List customers = new LinkedList<>(); + namedParameterTemplate.query(SELECT_NAMED_PARAMETERS, params, rs -> { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + customers.add(cust); }); assertEquals(1, customers.size()); @@ -269,15 +251,12 @@ public class NamedParameterJdbcTemplateTests { given(resultSet.getInt("id")).willReturn(1); given(resultSet.getString("forename")).willReturn("rod"); - final List customers = new LinkedList(); - namedParameterTemplate.query(SELECT_NO_PARAMETERS, new RowCallbackHandler() { - @Override - public void processRow(ResultSet rs) throws SQLException { - Customer cust = new Customer(); - cust.setId(rs.getInt(COLUMN_NAMES[0])); - cust.setForename(rs.getString(COLUMN_NAMES[1])); - customers.add(cust); - } + final List customers = new LinkedList<>(); + namedParameterTemplate.query(SELECT_NO_PARAMETERS, rs -> { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + customers.add(cust); }); assertEquals(1, customers.size()); @@ -297,14 +276,11 @@ public class NamedParameterJdbcTemplateTests { params.put("id", new SqlParameterValue(Types.DECIMAL, 1)); params.put("country", "UK"); List customers = namedParameterTemplate.query(SELECT_NAMED_PARAMETERS, params, - new RowMapper() { - @Override - public Customer mapRow(ResultSet rs, int rownum) throws SQLException { - Customer cust = new Customer(); - cust.setId(rs.getInt(COLUMN_NAMES[0])); - cust.setForename(rs.getString(COLUMN_NAMES[1])); - return cust; - } + (rs, rownum) -> { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; }); assertEquals(1, customers.size()); assertTrue("Customer id was assigned correctly", customers.get(0).getId() == 1); @@ -323,14 +299,11 @@ public class NamedParameterJdbcTemplateTests { given(resultSet.getString("forename")).willReturn("rod"); List customers = namedParameterTemplate.query(SELECT_NO_PARAMETERS, - new RowMapper() { - @Override - public Customer mapRow(ResultSet rs, int rownum) throws SQLException { - Customer cust = new Customer(); - cust.setId(rs.getInt(COLUMN_NAMES[0])); - cust.setForename(rs.getString(COLUMN_NAMES[1])); - return cust; - } + (rs, rownum) -> { + Customer cust = new Customer(); + cust.setId(rs.getInt(COLUMN_NAMES[0])); + cust.setForename(rs.getString(COLUMN_NAMES[1])); + return cust; }); assertEquals(1, customers.size()); assertTrue("Customer id was assigned correctly", customers.get(0).getId() == 1); @@ -349,14 +322,11 @@ public class NamedParameterJdbcTemplateTests { params.put("id", new SqlParameterValue(Types.DECIMAL, 1)); params.put("country", "UK"); Customer cust = namedParameterTemplate.queryForObject(SELECT_NAMED_PARAMETERS, params, - new RowMapper() { - @Override - public Customer mapRow(ResultSet rs, int rownum) throws SQLException { - Customer cust = new Customer(); - cust.setId(rs.getInt(COLUMN_NAMES[0])); - cust.setForename(rs.getString(COLUMN_NAMES[1])); - return cust; - } + (rs, rownum) -> { + Customer cust1 = new Customer(); + cust1.setId(rs.getInt(COLUMN_NAMES[0])); + cust1.setForename(rs.getString(COLUMN_NAMES[1])); + return cust1; }); assertTrue("Customer id was assigned correctly", cust.getId() == 1); assertTrue("Customer forename was assigned correctly", cust.getForename().equals("rod")); @@ -405,15 +375,14 @@ public class NamedParameterJdbcTemplateTests { final Map[] ids = new Map[2]; ids[0] = Collections.singletonMap("id", 100); ids[1] = Collections.singletonMap("id", 200); - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] rowsAffected = new int[] {1, 2}; given(preparedStatement.executeBatch()).willReturn(rowsAffected); given(connection.getMetaData()).willReturn(databaseMetaData); + namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false)); - JdbcTemplate template = new JdbcTemplate(dataSource, false); - namedParameterTemplate = new NamedParameterJdbcTemplate(template); - int[] actualRowsAffected = namedParameterTemplate.batchUpdate("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids); - + int[] actualRowsAffected = namedParameterTemplate.batchUpdate( + "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids); assertTrue("executed 2 updates", actualRowsAffected.length == 2); assertEquals(rowsAffected[0], actualRowsAffected[0]); assertEquals(rowsAffected[1], actualRowsAffected[1]); @@ -425,20 +394,30 @@ public class NamedParameterJdbcTemplateTests { verify(connection, atLeastOnce()).close(); } + @Test + public void testBatchUpdateWithEmptyMap() throws Exception { + @SuppressWarnings("unchecked") + final Map[] ids = new Map[0]; + namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false)); + + int[] actualRowsAffected = namedParameterTemplate.batchUpdate( + "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids); + assertTrue("executed 0 updates", actualRowsAffected.length == 0); + } + @Test public void testBatchUpdateWithSqlParameterSource() throws Exception { SqlParameterSource[] ids = new SqlParameterSource[2]; ids[0] = new MapSqlParameterSource("id", 100); ids[1] = new MapSqlParameterSource("id", 200); - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] rowsAffected = new int[] {1, 2}; given(preparedStatement.executeBatch()).willReturn(rowsAffected); given(connection.getMetaData()).willReturn(databaseMetaData); + namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false)); - JdbcTemplate template = new JdbcTemplate(dataSource, false); - namedParameterTemplate = new NamedParameterJdbcTemplate(template); - int[] actualRowsAffected = namedParameterTemplate.batchUpdate("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids); - + int[] actualRowsAffected = namedParameterTemplate.batchUpdate( + "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids); assertTrue("executed 2 updates", actualRowsAffected.length == 2); assertEquals(rowsAffected[0], actualRowsAffected[0]); assertEquals(rowsAffected[1], actualRowsAffected[1]); @@ -455,15 +434,14 @@ public class NamedParameterJdbcTemplateTests { SqlParameterSource[] ids = new SqlParameterSource[2]; ids[0] = new MapSqlParameterSource().addValue("id", 100, Types.NUMERIC); ids[1] = new MapSqlParameterSource().addValue("id", 200, Types.NUMERIC); - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] rowsAffected = new int[] {1, 2}; given(preparedStatement.executeBatch()).willReturn(rowsAffected); given(connection.getMetaData()).willReturn(databaseMetaData); + namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false)); - JdbcTemplate template = new JdbcTemplate(dataSource, false); - namedParameterTemplate = new NamedParameterJdbcTemplate(template); - int[] actualRowsAffected = namedParameterTemplate.batchUpdate("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids); - + int[] actualRowsAffected = namedParameterTemplate.batchUpdate( + "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids); assertTrue("executed 2 updates", actualRowsAffected.length == 2); assertEquals(rowsAffected[0], actualRowsAffected[0]); assertEquals(rowsAffected[1], actualRowsAffected[1]);