From 9261ee216a448526b8f404337774074356fe7c23 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Fri, 12 Jan 2018 16:46:22 -0500 Subject: [PATCH] Fix mapping null enums, add tests --- .../jdbc/util/ResultSetUtil.java | 21 ++++++++++ .../jdbc/codegen/JdbcMapperTest.java | 15 +++++++ .../jdbc/codegen/PersonDAO.java | 9 ++++ .../jdbc/CompilingRowToObjectMapper.java | 42 +++++++++---------- .../jdbc/RowToObjectMapper.java | 9 ++-- .../moparisthebest/jdbc/QueryMapperTest.java | 24 ++++++++++- 6 files changed, 93 insertions(+), 27 deletions(-) diff --git a/common/src/main/java/com/moparisthebest/jdbc/util/ResultSetUtil.java b/common/src/main/java/com/moparisthebest/jdbc/util/ResultSetUtil.java index bbc783c..f29d657 100644 --- a/common/src/main/java/com/moparisthebest/jdbc/util/ResultSetUtil.java +++ b/common/src/main/java/com/moparisthebest/jdbc/util/ResultSetUtil.java @@ -110,6 +110,11 @@ public class ResultSetUtil { return c; } + public static > T getEnum(final ResultSet _resultSet, final int index, final Class enumType) throws SQLException { + final String name = _resultSet.getString(index); + return name == null ? null : Enum.valueOf(enumType, name); + } + //IFJAVA8_START public static Instant getInstant(final ResultSet _resultSet, final int index) throws SQLException { @@ -196,6 +201,22 @@ public class ResultSetUtil { return ts == null ? null : OffsetTime.ofInstant(ts.toInstant(), _cal.getTimeZone().toZoneId()); } + public static Year getYear(final ResultSet _resultSet, final int index) throws SQLException { + // done this way instead of of(int) because usually int->string database coercion is allowed and the other isn't? + final String s = _resultSet.getString(index); + return s == null ? null : Year.parse(s); + } + + public static ZoneId getZoneId(final ResultSet _resultSet, final int index) throws SQLException { + final String s = _resultSet.getString(index); + return s == null ? null : ZoneId.of(s); + } + + public static ZoneOffset getZoneOffset(final ResultSet _resultSet, final int index) throws SQLException { + final String s = _resultSet.getString(index); + return s == null ? null : ZoneOffset.of(s); + } + //IFJAVA8_END } diff --git a/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/JdbcMapperTest.java b/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/JdbcMapperTest.java index b2bc577..322a61b 100644 --- a/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/JdbcMapperTest.java +++ b/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/JdbcMapperTest.java @@ -101,11 +101,26 @@ public class JdbcMapperTest { assertEquals(new EnumPerson(FirstName.First), dao.getEnumPerson(fieldPerson1.getPersonNo())); } + @Test + public void testEnumPersonConstructor() throws SQLException { + assertEquals(new EnumPerson(FirstName.First), dao.getEnumPersonConstructor(fieldPerson1.getPersonNo())); + } + @Test public void testEnum() throws SQLException { assertEquals(FirstName.First, dao.getFirstNameEnum(fieldPerson1.getPersonNo())); } + @Test + public void testEnumPersonNull() throws SQLException { + assertEquals(new EnumPerson(null), dao.getEnumPersonNull()); + } + + @Test + public void testEnumNull() throws SQLException { + assertEquals(null, dao.getEnumNull()); + } + //IFJAVA8_START @Test diff --git a/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/PersonDAO.java b/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/PersonDAO.java index fd14558..939b174 100644 --- a/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/PersonDAO.java +++ b/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/PersonDAO.java @@ -196,9 +196,18 @@ public interface PersonDAO extends JdbcMapper { @JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE person_no = {personNo}") EnumPerson getEnumPerson(long personNo) throws SQLException; + @JdbcMapper.SQL("SELECT first_name FROM person WHERE person_no = {personNo}") + EnumPerson getEnumPersonConstructor(long personNo) throws SQLException; + @JdbcMapper.SQL("SELECT first_name FROM person WHERE person_no = {personNo}") FirstName getFirstNameEnum(long personNo) throws SQLException; + @JdbcMapper.SQL("SELECT str_val as first_name, str_val as last_name FROM val WHERE val_no = 4") + EnumPerson getEnumPersonNull() throws SQLException; + + @JdbcMapper.SQL("SELECT str_val FROM val WHERE val_no = 4") + FirstName getEnumNull() throws SQLException; + //IFJAVA8_START @JdbcMapper.SQL("SELECT birth_date FROM person WHERE person_no = {personNo}") diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/CompilingRowToObjectMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/CompilingRowToObjectMapper.java index 076471f..e3aa3e5 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/CompilingRowToObjectMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/CompilingRowToObjectMapper.java @@ -453,35 +453,35 @@ public class CompilingRowToObjectMapper extends RowToObjectMapper { java.append(resultSetName).append(".getInt(").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_BOOLEAN: - java.append("getBooleanYN(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getBooleanYN(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_INT_OBJ: - java.append("getObjectInt(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getObjectInt(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_LONG_OBJ: - java.append("getObjectLong(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getObjectLong(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_FLOAT_OBJ: - java.append("getObjectFloat(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getObjectFloat(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_DOUBLE_OBJ: - java.append("getObjectDouble(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getObjectDouble(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_BYTE_OBJ: - java.append("getObjectByte(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getObjectByte(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_SHORT_OBJ: - java.append("getObjectShort(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getObjectShort(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_BOOLEAN_OBJ: - java.append("getObjectBooleanYN(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getObjectBooleanYN(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_STRING: case TypeMappingsFactory.TYPE_XMLBEAN_ENUM: java.append(resultSetName).append(".getString(").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_ENUM: - java.append(enumName).append(".valueOf(").append(resultSetName).append(".getString(").append(String.valueOf(index)).append("))"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getEnum(").append(resultSetName).append(", ").append(String.valueOf(index)).append(", ").append(enumName).append(".class)"); return; case TypeMappingsFactory.TYPE_BIG_DECIMAL: java.append(resultSetName).append(".getBigDecimal(").append(String.valueOf(index)).append(")"); @@ -508,13 +508,13 @@ public class CompilingRowToObjectMapper extends RowToObjectMapper { java.append(")"); return; case TypeMappingsFactory.TYPE_DATE: - java.append("getUtilDate(").append(resultSetName).append(", ").append(String.valueOf(index)); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(").append(resultSetName).append(", ").append(String.valueOf(index)); if(calendarName != null) java.append(", ").append(calendarName); java.append(")"); return; case TypeMappingsFactory.TYPE_CALENDAR: - java.append("getCalendar(").append(resultSetName).append(", ").append(String.valueOf(index)); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getCalendar(").append(resultSetName).append(", ").append(String.valueOf(index)); if(calendarName != null) java.append(", ").append(calendarName); java.append(")"); @@ -536,56 +536,56 @@ public class CompilingRowToObjectMapper extends RowToObjectMapper { throw new MapperException("streaming return types are not supported by the JdbcControl; use ResultSet instead"); // start java.time support case TypeMappingsFactory.TYPE_INSTANT: - java.append("getInstant(").append(resultSetName).append(", ").append(String.valueOf(index)); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getInstant(").append(resultSetName).append(", ").append(String.valueOf(index)); if(calendarName != null) java.append(", ").append(calendarName); java.append(")"); return; case TypeMappingsFactory.TYPE_LOCALDATETIME: - java.append("getLocalDateTime(").append(resultSetName).append(", ").append(String.valueOf(index)); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getLocalDateTime(").append(resultSetName).append(", ").append(String.valueOf(index)); if(calendarName != null) java.append(", ").append(calendarName); java.append(")"); return; case TypeMappingsFactory.TYPE_LOCALDATE: - java.append("getLocalDate(").append(resultSetName).append(", ").append(String.valueOf(index)); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getLocalDate(").append(resultSetName).append(", ").append(String.valueOf(index)); if(calendarName != null) java.append(", ").append(calendarName); java.append(")"); return; case TypeMappingsFactory.TYPE_LOCALTIME: - java.append("getLocalTime(").append(resultSetName).append(", ").append(String.valueOf(index)); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getLocalTime(").append(resultSetName).append(", ").append(String.valueOf(index)); if(calendarName != null) java.append(", ").append(calendarName); java.append(")"); return; // todo: send in ZoneId here? case TypeMappingsFactory.TYPE_ZONEDDATETIME: - java.append("getZonedDateTime(").append(resultSetName).append(", ").append(String.valueOf(index)); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getZonedDateTime(").append(resultSetName).append(", ").append(String.valueOf(index)); if(calendarName != null) java.append(", ").append(calendarName); java.append(")"); return; case TypeMappingsFactory.TYPE_OFFSETDATETIME: - java.append("getOffsetDateTime(").append(resultSetName).append(", ").append(String.valueOf(index)); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getOffsetDateTime(").append(resultSetName).append(", ").append(String.valueOf(index)); if(calendarName != null) java.append(", ").append(calendarName); java.append(")"); return; case TypeMappingsFactory.TYPE_OFFSETTIME: - java.append("getOffsetTime(").append(resultSetName).append(", ").append(String.valueOf(index)); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getOffsetTime(").append(resultSetName).append(", ").append(String.valueOf(index)); if(calendarName != null) java.append(", ").append(calendarName); java.append(")"); return; case TypeMappingsFactory.TYPE_YEAR: - java.append("java.time.Year.parse(").append(resultSetName).append(".getString(").append(String.valueOf(index)).append("))"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getYear(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_ZONEID: - java.append("java.time.ZoneId.of(").append(resultSetName).append(".getString(").append(String.valueOf(index)).append("))"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getZoneId(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; case TypeMappingsFactory.TYPE_ZONEOFFSET: - java.append("java.time.ZoneOffset.of(").append(resultSetName).append(".getString(").append(String.valueOf(index)).append("))"); + java.append("com.moparisthebest.jdbc.util.ResultSetUtil.getZoneOffset(").append(resultSetName).append(", ").append(String.valueOf(index)).append(")"); return; // end java.time support case TypeMappingsFactory.TYPE_STRUCT: diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java index 1ae4eb3..243c91a 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java @@ -654,7 +654,7 @@ public class RowToObjectMapper extends AbstractRowMapper { return _resultSet.getString(index); case TypeMappingsFactory.TYPE_ENUM: @SuppressWarnings("unchecked") - final Enum ret = Enum.valueOf((Class)resultTypeClass, _resultSet.getString(index)); + final Enum ret = ResultSetUtil.getEnum(_resultSet, index, (Class) resultTypeClass); return ret; case TypeMappingsFactory.TYPE_BIG_DECIMAL: return _resultSet.getBigDecimal(index); @@ -728,12 +728,11 @@ public class RowToObjectMapper extends AbstractRowMapper { case TypeMappingsFactory.TYPE_OFFSETTIME: return ResultSetUtil.getOffsetTime(_resultSet, index, _cal); case TypeMappingsFactory.TYPE_YEAR: - // done this way instead of of(int) because usually int->string database coercion is allowed and the other isn't? - return Year.parse(_resultSet.getString(index)); + return ResultSetUtil.getYear(_resultSet, index); case TypeMappingsFactory.TYPE_ZONEID: - return ZoneId.of(_resultSet.getString(index)); + return ResultSetUtil.getZoneId(_resultSet, index); case TypeMappingsFactory.TYPE_ZONEOFFSET: - return ZoneOffset.of(_resultSet.getString(index)); + return ResultSetUtil.getZoneOffset(_resultSet, index); // end java.time support //IFJAVA8_END case TypeMappingsFactory.TYPE_STRUCT: diff --git a/querymapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java b/querymapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java index e497adf..9c2489c 100644 --- a/querymapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java +++ b/querymapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java @@ -36,6 +36,8 @@ public class QueryMapperTest { public static final Person fieldPerson2 = new FieldPerson(5, new Date(0), "Second", "Person"); public static final Person fieldPerson3 = new FieldPerson(6, new Date(0), "Third", "Person"); + public static final Person fieldPerson1NullName = new FieldPerson(1, new Date(0), null, null); + public static final Person[] people = new Person[]{fieldPerson1, fieldPerson2, fieldPerson3}; public static final Boss[] bosses = new Boss[]{fieldBoss1, fieldBoss2, fieldBoss3}; @@ -43,6 +45,7 @@ public class QueryMapperTest { new Val(1, 1969, "1969"), new Val(2, 0, "America/New_York"), new Val(3, -5, "-5"), + new Val(4, 4, null), }; public static final Person setPerson1 = new SetPerson(fieldPerson1); @@ -91,7 +94,7 @@ public class QueryMapperTest { qm.executeUpdate("CREATE TABLE boss (person_no NUMERIC, department VARCHAR(40))"); qm.executeUpdate("CREATE TABLE val (val_no NUMERIC, num_val NUMERIC, str_val VARCHAR(40))"); for (final Person person : people) - qm.executeUpdate("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES (?, ?, ?, ?)", person.getPersonNo(), person.getBirthDate(), person.getLastName(), person.getFirstName()); + insertPerson(qm, person); for (final Boss boss : bosses) { qm.executeUpdate("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES (?, ?, ?, ?)", boss.getPersonNo(), boss.getBirthDate(), boss.getLastName(), boss.getFirstName() == null ? boss.getFirst_name() : boss.getFirstName()); qm.executeUpdate("INSERT INTO boss (person_no, department) VALUES (?, ?)", boss.getPersonNo(), boss.getDepartment()); @@ -108,6 +111,10 @@ public class QueryMapperTest { } } + public static void insertPerson(final QueryMapper qm, final Person person) throws SQLException { + qm.executeUpdate("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES (?, ?, ?, ?)", person.getPersonNo(), person.getBirthDate(), person.getLastName(), person.getFirstName()); + } + public static Connection getConnection() throws SQLException { return DriverManager.getConnection("jdbc:derby:memory:derbyDB;create=true"); } @@ -450,11 +457,26 @@ public class QueryMapperTest { assertEquals(new EnumPerson(FirstName.First), qm.toObject("SELECT first_name, last_name FROM person WHERE person_no = ?", EnumPerson.class, fieldPerson1.getPersonNo())); } + @Test + public void testEnumPersonConstructor() throws SQLException { + assertEquals(new EnumPerson(FirstName.First), qm.toObject("SELECT first_name FROM person WHERE person_no = ?", EnumPerson.class, fieldPerson1.getPersonNo())); + } + @Test public void testEnum() throws SQLException { assertEquals(FirstName.First, qm.toObject("SELECT first_name FROM person WHERE person_no = ?", FirstName.class, fieldPerson1.getPersonNo())); } + @Test + public void testEnumPersonNull() throws SQLException { + assertEquals(new EnumPerson(null), qm.toObject("SELECT str_val as first_name, str_val as last_name FROM val WHERE val_no = 4", EnumPerson.class)); + } + + @Test + public void testEnumNull() throws SQLException { + assertEquals(null, qm.toObject("SELECT str_val FROM val WHERE val_no = 4", FirstName.class)); + } + //IFJAVA8_START @Test