Skip to main content

Spring Note: RowMapper/MappingSqlQuery

There are a couple of interesting Spring classes which keep coming up in my daily work: RowMapper and MappingSqlQuery.

RowMapper

The RowMapper class is an interface which defines only one method which turns a single row from a ResultSet into a domain-useable object. While you can use a generic implementation of this class for producing column name/value Maps, my typical usage has been to create domain objects from the result of a specific set of queries.

MappingSqlQuery

The MappingSqlQuery class is intended to be used for SELECT queries and can use a RowMapper implementation to create a result List of the appropriate type, hiding the intermediate ResultSet from the outside world.

These classes, when taken together, provide excellent tools for creating the read methods for DAO classes which are concise and testable.

ITSpringJdbc.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ITSpringJdbc {

  public class TestMapper implements RowMapper {
    @Override
    public Map<String, String> mapRow(final ResultSet rs, final int index)
        throws SQLException {
      final Map<String, String> m = new HashMap<String, String>();
      final ResultSetMetaData md = rs.getMetaData();
      for (int i = 0; i < md.getColumnCount(); i++) {
        m.put(md.getColumnName(i), rs.getString(i));
      }
      return m;
    }
  }

  public class TestSelect extends MappingSqlQuery {
    final TestMapper mapper = new TestMapper();

    @Override
    protected Object mapRow(final ResultSet rs, final int index)
        throws SQLException {
      return mapper.mapRow(rs, index);
    }
  }

  @Resource TestSelect selectBean;
  @Resource TestMapper mappingBean;
  @Resource JdbcTemplate jdbcTemplate;

  @Test public void testSelect() {
    final String[] args = { "X" };
    final Object result = selectBean.findObject(args);
    assertThat(result, is(notNullValue());
    assertThat(result, is(Map.class));
    final Map map = (Map) result;
    assertThat(map, hasSize(1));
    assertThat(map.containsKey("dummy"), is(true));
    assertThat(map.get("dummy"), is("X"));
  }

  @Test public void testMapper() {
    final SqlRowSet rs = jdbcTemplate.queryForRowSet(
      "select dummy from table");
    final Object o = mappingBean.mapRow(rs, 0);
    assertThat(o, is(notNullValue());
    assertThat(o, is(Map.class));
    final Map map = (Map) o;
    assertThat(map, hasSize(1));
    assertThat(map.containsKey("dummy"), is(true));
    assertThat(map.get("dummy"), is("X"));
  }
}

ITSpringJdbc-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:util="http://www.springframework.org/schema/util"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<bean id="dataSource.properties"
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
    <list>
      <value>classpath:connection.properties</value>
    </list>
  </property>
</bean>

<bean id="dataSource"
  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="${driverClassName}" />
  <property name="url" value="${uri}" />
  <property name="username" value="${username}" />
  <property name="password" value="${password}" />
</bean>

<bean id="selectBean"
  class="TestSelect">
  <property name="dataSource" ref="dataSource" />
  <property name="sql">
    <value>
      select dummy from table where dummy = ?
    </value>
  </property>
  <property name="types">
    <list value-type="java.lang.Integer">
      <util:constant
        static-field="java.sql.Types.VARCHAR" />
    </list>
  </property>
</bean>

<bean id="mappingBean"
  class="TestMapper"/>

<bean id="jdbcTemplate"
  class="org.springframework.jdbc.core.JdbcTemplate">
  <property name="dataSource" ref="dataSource"/>
</bean>
</beans>

Comments

Popular posts from this blog

Using MonoDevelop to Create an ASP.NET Web Service

NOTE: instructions below are for MonoDevelop 2.6 Beta 2 - built on 2011-04-06 03:37:58+0000Getting StartedCreate a new ASP.NET Web Application in MonoDevelop: From the menu, select: File → New → Solution…Expand C#.Select ASP.NET → Web Application.Enter a name for the ASP.NET project that will be created in the solution in Name:.Change the root location for the solution in Location:, if desired.Change the name of the root solution in Solution Name:, if desired.The Results – IWhat you have after executing the new ASP.NET Web Application project wizard is a solution containing one ASP.NET Web Application project. In the default project view in MonoDevelop, you'll find the following items: Default.aspx – This is the default web form rendered and presented in the browser when http://<server>:<port>/ is accessed. Default.aspx.cs – This C# file contains the developer-created common code and event handlers which can be used to affect the processing of the form.Default.aspx.des…

Testing Toolbelt: SpringJUnit4ClassRunner

The org.springframework.test.context.junit4.SpringJUnit4ClassRunner class is another implementation of the JUnit TestRunner class which is used to enable various features of Spring for every run of the test class and every test within it. To use the features provided by the SpringJUnit4ClassRunner class, you need to mark the class using the RunWith annotation using SpringJUnit4ClassRunner as its parameter.In addition to the custom test runner, you will want to mark the class with the ContextConfiguration annotation. The ContextConfiguration annotation is used to mark classes which will automatically read a Spring configuration file and use it to create an ApplicationContext. By default, this file located at <package path>/<test class name>-context.xml. Use the locations argument to over-ride.The ApplicationContext used by the Spring-integrated test will only be loaded once for the whole test class. This behavior can be over-ridden by annotating a test method with the Dirti…