Skip to content

Commit 40efd22

Browse files
gopalldbclaude
andauthored
Fix NPE in getObject(int, Class<T>) when column value is NULL (#1222) (#1227)
getObject(int, Class<T>) was missing a null guard before passing objects to converters, causing NPE in DateConverter.toDate() and all other converters when used by Spring DataClassRowMapper, Hibernate, etc. Added null check in both DatabricksResultSet and ConverterHelper as defense-in-depth, consistent with getObject(int) and getObject(int, Map). ## Description <!-- Provide a brief summary of the changes made and the issue they aim to address.--> ## Testing <!-- Describe how the changes have been tested--> Added unit tests ## Additional Notes to the Reviewer <!-- Share any additional context or insights that may help the reviewer understand the changes better. This could include challenges faced, limitations, or compromises made during the development process. Also, mention any areas of the code that you would like the reviewer to focus on specifically. --> NO_CHANGELOG=true Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 50ba0aa commit 40efd22

4 files changed

Lines changed: 66 additions & 1 deletion

File tree

src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSet.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,6 +1865,9 @@ public void updateNClob(String columnLabel, Reader reader) throws SQLException {
18651865
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
18661866
checkIfClosed();
18671867
Object obj = getObjectInternal(columnIndex);
1868+
if (obj == null) {
1869+
return null;
1870+
}
18681871
int columnSqlType = resultSetMetaData.getColumnType(columnIndex);
18691872
try {
18701873
return (T) ConverterHelper.convertSqlTypeToSpecificJavaType(type, columnSqlType, obj);

src/main/java/com/databricks/jdbc/api/impl/converters/ConverterHelper.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ public static Object convertSqlTypeToJavaType(int columnSqlType, Object object)
472472
*/
473473
public static Object convertSqlTypeToSpecificJavaType(
474474
Class<?> javaType, int columnSqlType, Object obj) throws DatabricksSQLException {
475+
if (obj == null) {
476+
return null;
477+
}
475478
// Get the appropriate converter for the SQL type
476479
ObjectConverter converter = getConverterForSqlType(columnSqlType);
477480
if (javaType == String.class) {

src/test/java/com/databricks/jdbc/api/impl/DatabricksResultSetTest.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1259,8 +1259,52 @@ void testIsComplexTypeThrowsExceptionWhenComplexDatatypeSupportIsDisabled() thro
12591259
structException.getSQLState());
12601260
}
12611261

1262-
// --- Tests for TelemetryCollector caching in next() ---
1262+
@Test
1263+
void testGetObjectWithClassType_NullDate_ReturnsNull() throws SQLException {
1264+
DatabricksResultSet resultSet = getResultSet(StatementState.SUCCEEDED, null);
1265+
when(mockedExecutionResult.getObject(0)).thenReturn(null);
1266+
1267+
assertNull(resultSet.getObject(1, Date.class));
1268+
assertTrue(resultSet.wasNull());
1269+
}
1270+
1271+
@Test
1272+
void testGetObjectWithClassType_NullTimestamp_ReturnsNull() throws SQLException {
1273+
DatabricksResultSet resultSet = getResultSet(StatementState.SUCCEEDED, null);
1274+
when(mockedExecutionResult.getObject(0)).thenReturn(null);
1275+
1276+
assertNull(resultSet.getObject(1, Timestamp.class));
1277+
assertTrue(resultSet.wasNull());
1278+
}
1279+
1280+
@Test
1281+
void testGetObjectWithClassType_NullLocalDate_ReturnsNull() throws SQLException {
1282+
DatabricksResultSet resultSet = getResultSet(StatementState.SUCCEEDED, null);
1283+
when(mockedExecutionResult.getObject(0)).thenReturn(null);
12631284

1285+
assertNull(resultSet.getObject(1, LocalDate.class));
1286+
assertTrue(resultSet.wasNull());
1287+
}
1288+
1289+
@Test
1290+
void testGetObjectWithClassType_NullInteger_ReturnsNull() throws SQLException {
1291+
DatabricksResultSet resultSet = getResultSet(StatementState.SUCCEEDED, null);
1292+
when(mockedExecutionResult.getObject(0)).thenReturn(null);
1293+
1294+
assertNull(resultSet.getObject(1, Integer.class));
1295+
assertTrue(resultSet.wasNull());
1296+
}
1297+
1298+
@Test
1299+
void testGetObjectWithClassType_NullString_ReturnsNull() throws SQLException {
1300+
DatabricksResultSet resultSet = getResultSet(StatementState.SUCCEEDED, null);
1301+
when(mockedExecutionResult.getObject(0)).thenReturn(null);
1302+
1303+
assertNull(resultSet.getObject(1, String.class));
1304+
assertTrue(resultSet.wasNull());
1305+
}
1306+
1307+
// --- Tests for TelemetryCollector caching in next() ---
12641308
private DatabricksResultSet getResultSetWithTelemetry() throws SQLException {
12651309
DatabricksConnection mockConnection = mock(DatabricksConnection.class);
12661310
IDatabricksConnectionContext mockContext = mock(IDatabricksConnectionContext.class);

src/test/java/com/databricks/jdbc/api/impl/converters/ConverterHelperTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,19 @@ void whenColumnType_Other() {
228228
ObjectConverter converter = ConverterHelper.getConverterForSqlType(Types.DECIMAL);
229229
assertInstanceOf(BigDecimalConverter.class, converter);
230230
}
231+
232+
@Test
233+
void testConvertSqlTypeToSpecificJavaType_NullObject_ReturnsNull() throws DatabricksSQLException {
234+
assertNull(ConverterHelper.convertSqlTypeToSpecificJavaType(Date.class, Types.DATE, null));
235+
assertNull(
236+
ConverterHelper.convertSqlTypeToSpecificJavaType(Timestamp.class, Types.TIMESTAMP, null));
237+
assertNull(ConverterHelper.convertSqlTypeToSpecificJavaType(LocalDate.class, Types.DATE, null));
238+
assertNull(ConverterHelper.convertSqlTypeToSpecificJavaType(String.class, Types.VARCHAR, null));
239+
assertNull(
240+
ConverterHelper.convertSqlTypeToSpecificJavaType(Integer.class, Types.INTEGER, null));
241+
assertNull(ConverterHelper.convertSqlTypeToSpecificJavaType(Long.class, Types.BIGINT, null));
242+
assertNull(ConverterHelper.convertSqlTypeToSpecificJavaType(Double.class, Types.DOUBLE, null));
243+
assertNull(
244+
ConverterHelper.convertSqlTypeToSpecificJavaType(BigDecimal.class, Types.DECIMAL, null));
245+
}
231246
}

0 commit comments

Comments
 (0)