Merge pull request #132 from mminella/BATCH-1955

BATCH-1955: Removed requirement to inject ItemSqlParamterSourceProvider ...
This commit is contained in:
Michael Minella
2013-03-01 09:55:35 -08:00
2 changed files with 66 additions and 51 deletions

View File

@@ -19,6 +19,7 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
@@ -55,6 +56,7 @@ import org.springframework.util.Assert;
*
* @author Dave Syer
* @author Thomas Risberg
* @author Michael Minella
* @since 2.0
*/
public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
@@ -106,7 +108,8 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
/**
* Public setter for the {@link ItemSqlParameterSourceProvider}.
* @param itemSqlParameterSourceProvider the {@link ItemSqlParameterSourceProvider} to
* set. This is required when using named parameters for the SQL statement.
* set. This is required when using named parameters for the SQL statement and the type
* to be written does not implement {@link Map}.
*/
public void setItemSqlParameterSourceProvider(ItemSqlParameterSourceProvider<T> itemSqlParameterSourceProvider) {
this.itemSqlParameterSourceProvider = itemSqlParameterSourceProvider;
@@ -147,10 +150,7 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
usingNamedParameters = true;
}
if (usingNamedParameters) {
Assert.notNull(itemSqlParameterSourceProvider, "Using SQL statement with named parameters requires an ItemSqlParameterSourceProvider");
}
else {
if (!usingNamedParameters) {
Assert.notNull(itemPreparedStatementSetter, "Using SQL statement with '?' placeholders requires an ItemPreparedStatementSetter");
}
}
@@ -159,6 +159,7 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
*/
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public void write(final List<? extends T> items) throws Exception {
if (!items.isEmpty()) {
@@ -170,12 +171,16 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
int[] updateCounts = null;
if (usingNamedParameters) {
SqlParameterSource[] batchArgs = new SqlParameterSource[items.size()];
int i = 0;
for (T item : items) {
batchArgs[i++] = itemSqlParameterSourceProvider.createSqlParameterSource(item);
if(items.get(0) instanceof Map) {
updateCounts = namedParameterJdbcTemplate.batchUpdate(sql, items.toArray(new Map[0]));
} else {
SqlParameterSource[] batchArgs = new SqlParameterSource[items.size()];
int i = 0;
for (T item : items) {
batchArgs[i++] = itemSqlParameterSourceProvider.createSqlParameterSource(item);
}
updateCounts = namedParameterJdbcTemplate.batchUpdate(sql, batchArgs);
}
updateCounts = namedParameterJdbcTemplate.batchUpdate(sql, batchArgs);
}
else {
updateCounts = (int[]) namedParameterJdbcTemplate.getJdbcOperations().execute(sql, new PreparedStatementCallback() {

View File

@@ -24,11 +24,14 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@@ -37,13 +40,15 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
/**
* @author Thomas Risberg
* @author Will Schipp
* @author Michael Minella
*/
@SuppressWarnings({"rawtypes", "serial", "unchecked"})
public class JdbcBatchItemWriterNamedParameterTests {
private JdbcBatchItemWriter<Foo> writer = new JdbcBatchItemWriter<Foo>();
private JdbcBatchItemWriter writer = new JdbcBatchItemWriter<Foo>();
private NamedParameterJdbcOperations namedParameterJdbcOperations;
private NamedParameterJdbcOperations namedParameterJdbcOperations;
private String sql = "update foo set bar = :bar where id = :id";
@SuppressWarnings("unused")
@@ -55,7 +60,7 @@ public class JdbcBatchItemWriterNamedParameterTests {
this.id = 1L;
this.bar = bar;
}
public Long getId() {
return id;
}
@@ -71,12 +76,12 @@ public class JdbcBatchItemWriterNamedParameterTests {
public void setBar(String bar) {
this.bar = bar;
}
}
@Before
public void setUp() throws Exception {
namedParameterJdbcOperations = mock(NamedParameterJdbcOperations.class);
namedParameterJdbcOperations = mock(NamedParameterJdbcOperations.class);
writer.setSql(sql);
writer.setJdbcTemplate(namedParameterJdbcOperations);
writer.setItemSqlParameterSourceProvider(
@@ -113,22 +118,27 @@ public class JdbcBatchItemWriterNamedParameterTests {
assertTrue("Message does not contain 'sql'.", message.indexOf("sql") >= 0);
}
writer.setSql("select * from foo where id = :id");
try {
writer.afterPropertiesSet();
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
// expected
String message = e.getMessage();
assertTrue("Message does not contain 'ItemSqlParameterSourceProvider'.", message.indexOf("ItemSqlParameterSourceProvider") >= 0);
}
writer.setItemSqlParameterSourceProvider(
new BeanPropertyItemSqlParameterSourceProvider<Foo>());
writer.afterPropertiesSet();
}
@Test
public void testWriteAndFlush() throws Exception {
writer.setItemSqlParameterSourceProvider(null);
ArgumentCaptor<Map []> captor = ArgumentCaptor.forClass(Map[].class);
when(namedParameterJdbcOperations.batchUpdate(eq(sql),
captor.capture()))
.thenReturn(new int[] {1});
writer.write(Collections.singletonList(new HashMap<String, Object>() {{put("foo", "bar");}}));
assertEquals(1, captor.getValue().length);
Map<String, Object> results = captor.getValue()[0];
assertEquals("bar", results.get("foo"));
}
@Test
public void testWriteAndFlushMap() throws Exception {
when(namedParameterJdbcOperations.batchUpdate(eq(sql),
eqSqlParameterSourceArray(new SqlParameterSource[] {new BeanPropertySqlParameterSource(new Foo("bar"))})))
.thenReturn(new int[] {1});
@@ -168,42 +178,42 @@ public class JdbcBatchItemWriterNamedParameterTests {
public static SqlParameterSource[] eqSqlParameterSourceArray(SqlParameterSource[] in) {
argThat(new SqlParameterSourceArrayEquals(in));
return null;
return null;
}
public static class SqlParameterSourceArrayEquals extends BaseMatcher<SqlParameterSource[]> {
private SqlParameterSource[] expected;
private SqlParameterSource[] expected;
public SqlParameterSourceArrayEquals(SqlParameterSource[] expected) {
this.expected = expected;
}
public SqlParameterSourceArrayEquals(SqlParameterSource[] expected) {
this.expected = expected;
}
@Override
public boolean matches(Object actual) {
if (!(actual instanceof SqlParameterSource[])) {
return false;
}
SqlParameterSource[] actualArray = (SqlParameterSource[])actual;
if (expected.length != actualArray.length) {
return false;
}
for (int i = 0; i < expected.length; i++) {
if (!expected[i].getClass().equals(actualArray[i].getClass())) {
return false;
}
}
return true;
}
@Override
public boolean matches(Object actual) {
if (!(actual instanceof SqlParameterSource[])) {
return false;
}
SqlParameterSource[] actualArray = (SqlParameterSource[])actual;
if (expected.length != actualArray.length) {
return false;
}
for (int i = 0; i < expected.length; i++) {
if (!expected[i].getClass().equals(actualArray[i].getClass())) {
return false;
}
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText("eqSqlParameterSourceArray(");
description.appendText("eqSqlParameterSourceArray(");
description.appendText(expected.getClass().getName());
description.appendText(" with length \"");
description.appendValue(expected.length);
description.appendText("\")");
description.appendText("\")");
}
}
}
}