From e0329306dffd31ca4f3b9dfd5167b4f7e612158e Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 13 Jul 2015 21:30:57 +0200 Subject: [PATCH] JdbcTemplate's queryForObject allows for specifying primitive types as well Issue: SPR-13220 --- .../jdbc/core/BeanPropertyRowMapper.java | 14 ++++---- .../jdbc/core/SingleColumnRowMapper.java | 22 ++++++------ .../jdbc/core/JdbcTemplateQueryTests.java | 35 +++++++++++++++++-- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java index d277b0cab0..1192052900 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java @@ -92,7 +92,7 @@ public class BeanPropertyRowMapper implements RowMapper { /** - * Create a new BeanPropertyRowMapper for bean-style configuration. + * Create a new {@code BeanPropertyRowMapper} for bean-style configuration. * @see #setMappedClass * @see #setCheckFullyPopulated */ @@ -100,8 +100,8 @@ public class BeanPropertyRowMapper implements RowMapper { } /** - * Create a new BeanPropertyRowMapper, accepting unpopulated properties - * in the target bean. + * Create a new {@code BeanPropertyRowMapper}, accepting unpopulated + * properties in the target bean. *

Consider using the {@link #newInstance} factory method instead, * which allows for specifying the mapped type once only. * @param mappedClass the class that each row should be mapped to @@ -111,7 +111,7 @@ public class BeanPropertyRowMapper implements RowMapper { } /** - * Create a new BeanPropertyRowMapper. + * Create a new {@code BeanPropertyRowMapper}. * @param mappedClass the class that each row should be mapped to * @param checkFullyPopulated whether we're strictly validating that * all bean properties have been mapped from corresponding database fields @@ -326,14 +326,12 @@ public class BeanPropertyRowMapper implements RowMapper { /** - * Static factory method to create a new BeanPropertyRowMapper + * Static factory method to create a new {@code BeanPropertyRowMapper} * (with the mapped class specified only once). * @param mappedClass the class that each row should be mapped to */ public static BeanPropertyRowMapper newInstance(Class mappedClass) { - BeanPropertyRowMapper newInstance = new BeanPropertyRowMapper(); - newInstance.setMappedClass(mappedClass); - return newInstance; + return new BeanPropertyRowMapper(mappedClass); } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SingleColumnRowMapper.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SingleColumnRowMapper.java index f2f1292df2..69e4154b97 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SingleColumnRowMapper.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SingleColumnRowMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -23,6 +23,7 @@ import java.sql.SQLException; import org.springframework.dao.TypeMismatchDataAccessException; import org.springframework.jdbc.IncorrectResultSetColumnCountException; import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.util.ClassUtils; import org.springframework.util.NumberUtils; /** @@ -41,31 +42,34 @@ import org.springframework.util.NumberUtils; */ public class SingleColumnRowMapper implements RowMapper { - private Class requiredType; + private Class requiredType; /** - * Create a new SingleColumnRowMapper. + * Create a new {@code SingleColumnRowMapper} for bean-style configuration. * @see #setRequiredType */ public SingleColumnRowMapper() { } /** - * Create a new SingleColumnRowMapper. + * Create a new {@code SingleColumnRowMapper}. + *

Consider using the {@link #newInstance} factory method instead, + * which allows for specifying the required type once only. * @param requiredType the type that each result object is expected to match */ public SingleColumnRowMapper(Class requiredType) { - this.requiredType = requiredType; + setRequiredType(requiredType); } + /** * Set the type that each result object is expected to match. *

If not specified, the column value will be exposed as * returned by the JDBC driver. */ public void setRequiredType(Class requiredType) { - this.requiredType = requiredType; + this.requiredType = ClassUtils.resolvePrimitiveIfNecessary(requiredType); } @@ -187,15 +191,13 @@ public class SingleColumnRowMapper implements RowMapper { /** - * Static factory method to create a new ParameterizedSingleColumnRowMapper + * Static factory method to create a new {@code SingleColumnRowMapper} * (with the required type specified only once). * @param requiredType the type that each result object is expected to match * @since 4.1 */ public static SingleColumnRowMapper newInstance(Class requiredType) { - SingleColumnRowMapper newInstance = new SingleColumnRowMapper(); - newInstance.setRequiredType(requiredType); - return newInstance; + return new SingleColumnRowMapper(requiredType); } } diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateQueryTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateQueryTests.java index 721e08ca01..bbcc5657b6 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateQueryTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateQueryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -41,6 +41,7 @@ import static org.mockito.BDDMockito.*; /** * @author Juergen Hoeller * @author Phillip Webb + * @author Rob Winch * @since 19.12.2004 */ public class JdbcTemplateQueryTests { @@ -49,13 +50,20 @@ public class JdbcTemplateQueryTests { public ExpectedException thrown = ExpectedException.none(); private Connection connection; + private DataSource dataSource; + private Statement statement; + private PreparedStatement preparedStatement; + private ResultSet resultSet; + private ResultSetMetaData resultSetMetaData; + private JdbcTemplate template; + @Before public void setUp() throws Exception { this.connection = mock(Connection.class); @@ -75,6 +83,7 @@ public class JdbcTemplateQueryTests { given(this.statement.executeQuery(anyString())).willReturn(this.resultSet); } + @Test public void testQueryForList() throws Exception { String sql = "SELECT AGE FROM CUSTMR WHERE ID < 3"; @@ -219,7 +228,18 @@ public class JdbcTemplateQueryTests { String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; given(this.resultSet.next()).willReturn(true, false); given(this.resultSet.getInt(1)).willReturn(22); - int i = this.template.queryForObject(sql,Integer.class).intValue(); + int i = this.template.queryForObject(sql, Integer.class).intValue(); + assertEquals("Return of an int", 22, i); + verify(this.resultSet).close(); + verify(this.statement).close(); + } + + @Test + public void testQueryForIntPrimitive() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + given(this.resultSet.next()).willReturn(true, false); + given(this.resultSet.getInt(1)).willReturn(22); + int i = this.template.queryForObject(sql, int.class); assertEquals("Return of an int", 22, i); verify(this.resultSet).close(); verify(this.statement).close(); @@ -236,6 +256,17 @@ public class JdbcTemplateQueryTests { verify(this.statement).close(); } + @Test + public void testQueryForLongPrimitive() throws Exception { + String sql = "SELECT AGE FROM CUSTMR WHERE ID = 3"; + given(this.resultSet.next()).willReturn(true, false); + given(this.resultSet.getLong(1)).willReturn(87L); + long l = this.template.queryForObject(sql, long.class); + assertEquals("Return of a long", 87, l); + verify(this.resultSet).close(); + verify(this.statement).close(); + } + @Test public void testQueryForListWithArgs() throws Exception { doTestQueryForListWithArgs("SELECT AGE FROM CUSTMR WHERE ID < ?");