Browse Source

Fix mapping null enums, add tests

moparisthebest 1 month ago
parent
commit
9261ee216a

+ 21 - 0
common/src/main/java/com/moparisthebest/jdbc/util/ResultSetUtil.java

@@ -110,6 +110,11 @@ public class ResultSetUtil {
 		return c;
 	}
 
+	public static <T extends Enum<T>> T getEnum(final ResultSet _resultSet, final int index, final Class<T> 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
 
 }

+ 15 - 0
jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/JdbcMapperTest.java

@@ -102,10 +102,25 @@ public class JdbcMapperTest {
 	}
 
 	@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

+ 9 - 0
jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/PersonDAO.java

@@ -197,8 +197,17 @@ public interface PersonDAO extends JdbcMapper {
 	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}")

+ 21 - 21
querymapper/src/main/java/com/moparisthebest/jdbc/CompilingRowToObjectMapper.java

@@ -453,35 +453,35 @@ public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
 				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<K, T> extends RowToObjectMapper<K, T> {
 				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<K, T> extends RowToObjectMapper<K, T> {
 				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:

+ 4 - 5
querymapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java

@@ -654,7 +654,7 @@ public class RowToObjectMapper<K, T> extends AbstractRowMapper<K, T> {
 					return _resultSet.getString(index);
 				case TypeMappingsFactory.TYPE_ENUM:
 					@SuppressWarnings("unchecked")
-					final Enum ret = Enum.valueOf((Class<? extends Enum>)resultTypeClass, _resultSet.getString(index));
+					final Enum ret = ResultSetUtil.getEnum(_resultSet, index, (Class<? extends Enum>) resultTypeClass);
 					return ret;
 				case TypeMappingsFactory.TYPE_BIG_DECIMAL:
 					return _resultSet.getBigDecimal(index);
@@ -728,12 +728,11 @@ public class RowToObjectMapper<K, T> extends AbstractRowMapper<K, T> {
 				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:

+ 23 - 1
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");
 	}
@@ -451,10 +458,25 @@ public class QueryMapperTest {
 	}
 
 	@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