JdbcUtils explicitly extracts SQL date/time for JSR-310 LocalDate/Time
Issue: SPR-14898
This commit is contained in:
parent
3b49aacb9f
commit
a0fee4657d
|
@ -125,8 +125,10 @@ public abstract class JdbcUtils {
|
|||
* @param rs is the ResultSet holding the data
|
||||
* @param index is the column index
|
||||
* @param requiredType the required value type (may be {@code null})
|
||||
* @return the value object
|
||||
* @return the value object (possibly not of the specified required type,
|
||||
* with further conversion steps necessary)
|
||||
* @throws SQLException if thrown by the JDBC API
|
||||
* @see #getResultSetValue(ResultSet, int)
|
||||
*/
|
||||
public static Object getResultSetValue(ResultSet rs, int index, Class<?> requiredType) throws SQLException {
|
||||
if (requiredType == null) {
|
||||
|
@ -182,6 +184,7 @@ public abstract class JdbcUtils {
|
|||
else if (Clob.class == requiredType) {
|
||||
return rs.getClob(index);
|
||||
}
|
||||
|
||||
else {
|
||||
// Some unknown type desired -> rely on getObject.
|
||||
try {
|
||||
|
@ -196,7 +199,22 @@ public abstract class JdbcUtils {
|
|||
catch (SQLException ex) {
|
||||
logger.debug("JDBC driver has limited support for JDBC 4.1 'getObject(int, Class)' method", ex);
|
||||
}
|
||||
// Fall back to getObject without type specification...
|
||||
|
||||
// Corresponding SQL types for JSR-310 / Joda-Time types, left up
|
||||
// to the caller to convert them (e.g. through a ConversionService).
|
||||
String typeName = requiredType.getSimpleName();
|
||||
if ("LocalDate".equals(typeName)) {
|
||||
return rs.getDate(index);
|
||||
}
|
||||
else if ("LocalTime".equals(typeName)) {
|
||||
return rs.getTime(index);
|
||||
}
|
||||
else if ("LocalDateTime".equals(typeName)) {
|
||||
return rs.getTimestamp(index);
|
||||
}
|
||||
|
||||
// Fall back to getObject without type specification, again
|
||||
// left up to the caller to convert the value if necessary.
|
||||
return getResultSetValue(rs, index);
|
||||
}
|
||||
|
||||
|
@ -248,7 +266,7 @@ public abstract class JdbcUtils {
|
|||
obj = rs.getDate(index);
|
||||
}
|
||||
}
|
||||
else if (obj != null && obj instanceof java.sql.Date) {
|
||||
else if (obj instanceof java.sql.Date) {
|
||||
if ("java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(index))) {
|
||||
obj = rs.getTimestamp(index);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.
|
||||
|
@ -20,10 +20,12 @@ import java.math.BigDecimal;
|
|||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import org.springframework.jdbc.core.test.ConcretePerson;
|
||||
import org.springframework.jdbc.core.test.DatePerson;
|
||||
import org.springframework.jdbc.core.test.Person;
|
||||
import org.springframework.jdbc.core.test.SpacePerson;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
|
@ -47,21 +49,30 @@ public abstract class AbstractRowMapperTests {
|
|||
assertEquals(new BigDecimal("1234.56"), bean.getBalance());
|
||||
}
|
||||
|
||||
protected void verifyConcretePerson(ConcretePerson bean) throws Exception {
|
||||
protected void verifyPerson(ConcretePerson bean) throws Exception {
|
||||
assertEquals("Bubba", bean.getName());
|
||||
assertEquals(22L, bean.getAge());
|
||||
assertEquals(new java.util.Date(1221222L), bean.getBirth_date());
|
||||
assertEquals(new BigDecimal("1234.56"), bean.getBalance());
|
||||
}
|
||||
|
||||
protected void verifySpacePerson(SpacePerson bean) {
|
||||
protected void verifyPerson(SpacePerson bean) {
|
||||
assertEquals("Bubba", bean.getLastName());
|
||||
assertEquals(22L, bean.getAge());
|
||||
assertEquals(new java.util.Date(1221222L), bean.getBirthDate());
|
||||
assertEquals(new java.sql.Timestamp(1221222L).toLocalDateTime(), bean.getBirthDate());
|
||||
assertEquals(new BigDecimal("1234.56"), bean.getBalance());
|
||||
}
|
||||
|
||||
protected static enum MockType {ONE,TWO,THREE};
|
||||
protected void verifyPerson(DatePerson bean) {
|
||||
assertEquals("Bubba", bean.getLastName());
|
||||
assertEquals(22L, bean.getAge());
|
||||
assertEquals(new java.sql.Date(1221222L).toLocalDate(), bean.getBirthDate());
|
||||
assertEquals(new BigDecimal("1234.56"), bean.getBalance());
|
||||
}
|
||||
|
||||
|
||||
protected enum MockType {ONE, TWO, THREE};
|
||||
|
||||
|
||||
protected static class Mock {
|
||||
|
||||
|
@ -79,8 +90,7 @@ public abstract class AbstractRowMapperTests {
|
|||
this(MockType.ONE);
|
||||
}
|
||||
|
||||
public Mock(MockType type)
|
||||
throws Exception {
|
||||
public Mock(MockType type) throws Exception {
|
||||
connection = mock(Connection.class);
|
||||
statement = mock(Statement.class);
|
||||
resultSet = mock(ResultSet.class);
|
||||
|
@ -94,6 +104,8 @@ public abstract class AbstractRowMapperTests {
|
|||
given(resultSet.getString(1)).willReturn("Bubba");
|
||||
given(resultSet.getLong(2)).willReturn(22L);
|
||||
given(resultSet.getTimestamp(3)).willReturn(new Timestamp(1221222L));
|
||||
given(resultSet.getObject(anyInt(), any(Class.class))).willThrow(new SQLFeatureNotSupportedException());
|
||||
given(resultSet.getDate(3)).willReturn(new java.sql.Date(1221222L));
|
||||
given(resultSet.getBigDecimal(4)).willReturn(new BigDecimal("1234.56"));
|
||||
given(resultSet.wasNull()).willReturn(type == MockType.TWO ? true : false);
|
||||
|
||||
|
@ -119,4 +131,5 @@ public abstract class AbstractRowMapperTests {
|
|||
verify(statement).close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.junit.rules.ExpectedException;
|
|||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.core.test.ConcretePerson;
|
||||
import org.springframework.jdbc.core.test.DatePerson;
|
||||
import org.springframework.jdbc.core.test.ExtendedPerson;
|
||||
import org.springframework.jdbc.core.test.Person;
|
||||
import org.springframework.jdbc.core.test.SpacePerson;
|
||||
|
@ -40,6 +41,7 @@ public class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
|
|||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void testOverridingDifferentClassDefinedForMapping() {
|
||||
|
@ -72,7 +74,7 @@ public class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
|
|||
"select name, age, birth_date, balance from people",
|
||||
new BeanPropertyRowMapper<>(ConcretePerson.class));
|
||||
assertEquals(1, result.size());
|
||||
verifyConcretePerson(result.get(0));
|
||||
verifyPerson(result.get(0));
|
||||
mock.verifyClosed();
|
||||
}
|
||||
|
||||
|
@ -83,7 +85,7 @@ public class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
|
|||
"select name, age, birth_date, balance from people",
|
||||
new BeanPropertyRowMapper<>(ConcretePerson.class, true));
|
||||
assertEquals(1, result.size());
|
||||
verifyConcretePerson(result.get(0));
|
||||
verifyPerson(result.get(0));
|
||||
mock.verifyClosed();
|
||||
}
|
||||
|
||||
|
@ -95,7 +97,7 @@ public class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
|
|||
new BeanPropertyRowMapper<>(ExtendedPerson.class));
|
||||
assertEquals(1, result.size());
|
||||
ExtendedPerson bean = result.get(0);
|
||||
verifyConcretePerson(bean);
|
||||
verifyPerson(bean);
|
||||
mock.verifyClosed();
|
||||
}
|
||||
|
||||
|
@ -118,13 +120,25 @@ public class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testQueryWithSpaceInColumnName() throws Exception {
|
||||
public void testQueryWithSpaceInColumnNameAndLocalDateTime() throws Exception {
|
||||
Mock mock = new Mock(MockType.THREE);
|
||||
List<SpacePerson> result = mock.getJdbcTemplate().query(
|
||||
"select last_name as \"Last Name\", age, birth_date, balance from people",
|
||||
new BeanPropertyRowMapper<>(SpacePerson.class));
|
||||
assertEquals(1, result.size());
|
||||
verifySpacePerson(result.get(0));
|
||||
verifyPerson(result.get(0));
|
||||
mock.verifyClosed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryWithSpaceInColumnNameAndLocalDate() throws Exception {
|
||||
Mock mock = new Mock(MockType.THREE);
|
||||
List<DatePerson> result = mock.getJdbcTemplate().query(
|
||||
"select last_name as \"Last Name\", age, birth_date, balance from people",
|
||||
new BeanPropertyRowMapper<>(DatePerson.class));
|
||||
assertEquals(1, result.size());
|
||||
verifyPerson(result.get(0));
|
||||
mock.verifyClosed();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class DatePerson {
|
||||
|
||||
private String lastName;
|
||||
|
||||
private long age;
|
||||
|
||||
private LocalDate birthDate;
|
||||
|
||||
private BigDecimal balance;
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public long getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(long age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public LocalDate getBirthDate() {
|
||||
return birthDate;
|
||||
}
|
||||
|
||||
public void setBirthDate(LocalDate birthDate) {
|
||||
this.birthDate = birthDate;
|
||||
}
|
||||
|
||||
public BigDecimal getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public void setBalance(BigDecimal balanace) {
|
||||
this.balance = balanace;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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.
|
||||
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.jdbc.core.test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author Thomas Risberg
|
||||
|
@ -27,7 +28,7 @@ public class SpacePerson {
|
|||
|
||||
private long age;
|
||||
|
||||
private java.util.Date birthDate;
|
||||
private LocalDateTime birthDate;
|
||||
|
||||
private BigDecimal balance;
|
||||
|
||||
|
@ -47,11 +48,11 @@ public class SpacePerson {
|
|||
this.age = age;
|
||||
}
|
||||
|
||||
public java.util.Date getBirthDate() {
|
||||
public LocalDateTime getBirthDate() {
|
||||
return birthDate;
|
||||
}
|
||||
|
||||
public void setBirth_date(java.util.Date birthDate) {
|
||||
public void setBirthDate(LocalDateTime birthDate) {
|
||||
this.birthDate = birthDate;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue