From 7287baefeb6ba9d43acc65034f0553b52990c557 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 19 Jul 2016 18:44:06 +0200 Subject: [PATCH] GenericSqlQuery configured with RowMapper instance Issue: SPR-14489 --- .../jdbc/object/GenericSqlQuery.java | 54 ++++++++++++------- .../jdbc/object/GenericSqlQueryTests.java | 17 ++++-- .../object/GenericSqlQueryTests-context.xml | 26 ++++++++- 3 files changed, 71 insertions(+), 26 deletions(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java b/spring-jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java index d2af62814c4..dbbfd5c1e05 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 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. @@ -18,43 +18,57 @@ package org.springframework.jdbc.object; import java.util.Map; -import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.beans.BeanUtils; import org.springframework.jdbc.core.RowMapper; import org.springframework.util.Assert; +/** + * A concrete variant of {@link SqlQuery} which can be configured + * with a {@link RowMapper}. + * + * @author Thomas Risberg + * @author Juergen Hoeller + * @since 3.0 + * @see #setRowMapper + * @see #setRowMapperClass + */ public class GenericSqlQuery extends SqlQuery { - Class rowMapperClass; + private RowMapper rowMapper; + + @SuppressWarnings("rawtypes") + private Class rowMapperClass; + - RowMapper rowMapper; + /** + * Set a specific {@link RowMapper} instance to use for this query. + * @since 4.3.2 + */ + public void setRowMapper(RowMapper rowMapper) { + this.rowMapper = rowMapper; + } + /** + * Set a {@link RowMapper} class for this query, creating a fresh + * {@link RowMapper} instance per execution. + */ @SuppressWarnings("rawtypes") - public void setRowMapperClass(Class rowMapperClass) - throws IllegalAccessException, InstantiationException { + public void setRowMapperClass(Class rowMapperClass) { this.rowMapperClass = rowMapperClass; - if (!RowMapper.class.isAssignableFrom(rowMapperClass)) - throw new IllegalStateException("The specified class '" + - rowMapperClass.getName() + " is not a sub class of " + - "'org.springframework.jdbc.core.RowMapper'"); } @Override public void afterPropertiesSet() { super.afterPropertiesSet(); - Assert.notNull(rowMapperClass, "The 'rowMapperClass' property is required"); + Assert.isTrue(this.rowMapper != null || this.rowMapperClass != null, + "'rowMapper' or 'rowMapperClass' is required"); } + @Override @SuppressWarnings("unchecked") protected RowMapper newRowMapper(Object[] parameters, Map context) { - try { - return (RowMapper) rowMapperClass.newInstance(); - } - catch (InstantiationException e) { - throw new InvalidDataAccessResourceUsageException("Unable to instantiate RowMapper", e); - } - catch (IllegalAccessException e) { - throw new InvalidDataAccessResourceUsageException("Unable to instantiate RowMapper", e); - } + return (this.rowMapper != null ? this.rowMapper : BeanUtils.instantiateClass(this.rowMapperClass)); } + } diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/object/GenericSqlQueryTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/object/GenericSqlQueryTests.java index 66a0432538a..dda92636838 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/object/GenericSqlQueryTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/object/GenericSqlQueryTests.java @@ -16,7 +16,6 @@ package org.springframework.jdbc.object; - import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -43,11 +42,12 @@ import static org.mockito.BDDMockito.*; /** * @author Thomas Risberg + * @author Juergen Hoeller */ public class GenericSqlQueryTests { private static final String SELECT_ID_FORENAME_NAMED_PARAMETERS_PARSED = - "select id, forename from custmr where id = ? and country = ?"; + "select id, forename from custmr where id = ? and country = ?"; private BeanFactory beanFactory; @@ -57,6 +57,7 @@ public class GenericSqlQueryTests { private ResultSet resultSet; + @Before public void setUp() throws Exception { this.beanFactory = new DefaultListableBeanFactory(); @@ -72,17 +73,23 @@ public class GenericSqlQueryTests { } @Test - public void testPlaceHoldersCustomerQuery() throws SQLException { - SqlQuery query = (SqlQuery) beanFactory.getBean("queryWithPlaceHolders"); + public void testCustomerQueryWithPlaceholders() throws SQLException { + SqlQuery query = (SqlQuery) beanFactory.getBean("queryWithPlaceholders"); doTestCustomerQuery(query, false); } @Test - public void testNamedParameterCustomerQuery() throws SQLException { + public void testCustomerQueryWithNamedParameters() throws SQLException { SqlQuery query = (SqlQuery) beanFactory.getBean("queryWithNamedParameters"); doTestCustomerQuery(query, true); } + @Test + public void testCustomerQueryWithRowMapperInstance() throws SQLException { + SqlQuery query = (SqlQuery) beanFactory.getBean("queryWithRowMapperBean"); + doTestCustomerQuery(query, true); + } + private void doTestCustomerQuery(SqlQuery query, boolean namedParameters) throws SQLException { given(resultSet.next()).willReturn(true); given(resultSet.getInt("id")).willReturn(1); diff --git a/spring-jdbc/src/test/resources/org/springframework/jdbc/object/GenericSqlQueryTests-context.xml b/spring-jdbc/src/test/resources/org/springframework/jdbc/object/GenericSqlQueryTests-context.xml index 908653e3fd0..719502060c2 100644 --- a/spring-jdbc/src/test/resources/org/springframework/jdbc/object/GenericSqlQueryTests-context.xml +++ b/spring-jdbc/src/test/resources/org/springframework/jdbc/object/GenericSqlQueryTests-context.xml @@ -6,7 +6,7 @@ - + @@ -50,4 +50,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file