Skip to content

fix: support getObject(Class) with identity class type in QueryJDBCAccessor#186

Open
mkaufmann wants to merge 1 commit into
mainfrom
moritz/getobject-class-base-fallback
Open

fix: support getObject(Class) with identity class type in QueryJDBCAccessor#186
mkaufmann wants to merge 1 commit into
mainfrom
moritz/getobject-class-base-fallback

Conversation

@mkaufmann
Copy link
Copy Markdown
Member

@mkaufmann mkaufmann commented May 11, 2026

QueryJDBCAccessor.getObject(Class) threw Operation not supported even for the identity type (like String for Varchar) which is highly surprising.

The base class implementation now handles the trivial cases:

  • reject if passed in type class object is null
  • fetch the raw object, return null if it's null, return it cast to T if type.isInstance(raw), otherwise throw a typed conversion error.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.37%. Comparing base (1bda7d4) to head (f966f24).

Files with missing lines Patch % Lines
...atacloud/jdbc/core/accessor/QueryJDBCAccessor.java 75.00% 2 Missing and 1 partial ⚠️

❌ Your patch check has failed because the patch coverage (75.00%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff              @@
##               main     #186      +/-   ##
============================================
- Coverage     82.37%   82.37%   -0.01%     
- Complexity     1867     1871       +4     
============================================
  Files           125      125              
  Lines          5009     5020      +11     
  Branches        537      540       +3     
============================================
+ Hits           4126     4135       +9     
- Misses          641      642       +1     
- Partials        242      243       +1     
Components Coverage Δ
JDBC Core 83.14% <75.00%> (-0.01%) ⬇️
JDBC Main 40.69% <ø> (ø)
JDBC HTTP 90.30% <ø> (ø)
JDBC Utilities 65.25% <ø> (ø)
Spark Datasource ∅ <ø> (∅)
Files with missing lines Coverage Δ
...atacloud/jdbc/core/accessor/QueryJDBCAccessor.java 93.87% <75.00%> (-3.50%) ⬇️

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mkaufmann mkaufmann force-pushed the moritz/getobject-class-base-fallback branch 2 times, most recently from 70b40d3 to 09593d6 Compare May 11, 2026 18:31
@mkaufmann mkaufmann changed the title fix: provide default getObject(Class) fallback in QueryJDBCAccessor fix: provide identity getObject(Class) default in QueryJDBCAccessor May 11, 2026
@mkaufmann mkaufmann changed the title fix: provide identity getObject(Class) default in QueryJDBCAccessor fix: support getObject(Class) with identity class type in QueryJDBCAccessor May 11, 2026
@mkaufmann mkaufmann force-pushed the moritz/getobject-class-base-fallback branch 2 times, most recently from bf0ced3 to 6817dde Compare May 12, 2026 14:49
QueryJDBCAccessor.getObject(Class) threw "Operation not supported" no
matter what. That's a problem: JDBC says
ResultSet.getObject(int, Class<T>) is supposed to return the value as
T when the conversion is trivial, but every accessor that didn't
override it would throw, even on the identity case like
getObject(col, String.class) against a VARCHAR. Callers had to either
know which accessors implement typed conversion or wrap calls in
catch-and-retry.

The new default covers the trivial cases:

1. null type -> SQLException with SQLState 22023.
2. String.class -> delegate to getString(). JDBC 4.2 Table B-5
   mandates this conversion for every column type.
3. Otherwise raw + isInstance, accepting any supertype/interface
   match. wasNull is set defensively when the raw value is null so
   stale state from an earlier non-null read does not leak.
4. Anything left throws SQLFeatureNotSupportedException (matching the
   JDBC spec's expectation for unsupported conversions, and consistent
   with the existing TimeStampVectorAccessor override).

Numeric narrowing (e.g. getObject(col, Integer.class) on a BIGINT
column) is intentionally NOT handled here. The accessor-level
primitive getters (getInt, getShort, getByte) use unchecked Java
casts -- delegating to them would silently truncate Long.MAX_VALUE
to -1 instead of refusing. Accessors that need lossless cross-type
conversion override getObject(Class) (TimeStampVectorAccessor for
the Instant / OffsetDateTime / LocalDateTime / etc. paths).

Tests in StreamingResultSetMethodTest cover:
- getObjectWithClassUsesAccessorBaseFallback: identity case
  (VARCHAR -> String) goes through the inherited String fast-path.
- getObjectWithSupertypeOrInterfaceReturnsValue: Object.class and
  CharSequence.class both work via isInstance -- proves polymorphic
  callers (raw Object holders, generic tooling) aren't blocked.
- getObjectWithNullClassThrows: null type parameter raises
  SQLException with the expected "must not be null" message.
- getObjectWithIncompatibleClassThrows: requesting an unrelated type
  (String column, StringBuilder asked) raises the typed conversion
  error.
- getObjectWithClassReturnsNullForNullValue: a null column value
  short-circuits and returns null regardless of the requested type;
  wasNull() is true afterwards.
@mkaufmann mkaufmann force-pushed the moritz/getobject-class-base-fallback branch from 6817dde to f966f24 Compare May 12, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants