{"record":{"id":"204c31c8f3ebf8f5","repo":"tursodatabase/turso","slug":"unsupported-object-type-in-bindobject-x-getcl","errorCode":null,"errorMessage":"Unsupported object type in bindObject: \" + x.getClass().getName()","messagePattern":"Unsupported object type in bindObject: \" \\+ x\\.getClass\\(\\)\\.getName\\(\\)","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/core/TursoStatement.java","lineNumber":240,"sourceCode":"    }\n    if (x instanceof Byte) {\n      this.bindInt(parameterIndex, (Byte) x);\n    } else if (x instanceof Short) {\n      this.bindInt(parameterIndex, (Short) x);\n    } else if (x instanceof Integer) {\n      this.bindInt(parameterIndex, (Integer) x);\n    } else if (x instanceof Long) {\n      this.bindLong(parameterIndex, (Long) x);\n    } else if (x instanceof String) {\n      bindText(parameterIndex, (String) x);\n    } else if (x instanceof Float) {\n      bindDouble(parameterIndex, (Float) x);\n    } else if (x instanceof Double) {\n      bindDouble(parameterIndex, (Double) x);\n    } else if (x instanceof byte[]) {\n      bindBlob(parameterIndex, (byte[]) x);\n    } else {\n      throw new SQLException(\"Unsupported object type in bindObject: \" + x.getClass().getName());\n    }\n  }\n\n  /**\n   * Returns total number of changes.\n   *\n   * @throws SQLException If a database access error occurs\n   */\n  public long totalChanges() throws SQLException {\n    final long result = totalChanges(statementPointer);\n    if (result == -1) {\n      throw new SQLException(\"Exception while retrieving total number of changes\");\n    }\n\n    return result;\n  }\n\n  private native long totalChanges(long statementPointer) throws SQLException;","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/java/src/main/java/tech/turso/core/TursoStatement.java#L222-L258","documentation":"TursoStatement.bindObject dispatches on the runtime type of the argument and only accepts null, Integer, Long, String, Float, Double, and byte[]. Any other non-null type falls into the else branch and throws this SQLException naming the offending class. There is no implicit conversion for Boolean, Short, Byte, BigDecimal, java.util.Date, java.sql.Timestamp, java.time types, UUID, or enums.","triggerScenarios":"ps.setObject(i, Boolean.TRUE); ps.setObject(i, new Timestamp(...)); ps.setObject(i, BigDecimal.TEN); ps.setObject(i, someEnum); ps.setObject(i, UUID.randomUUID()); any generic DAO that forwards arbitrary objects to setObject.","commonSituations":"Generic ORM-lite layers and JDBC helpers that always call setObject; porting code from drivers with wider setObject type maps (PostgreSQL/MySQL accept many more types); domain objects with enums or money types bound directly.","solutions":["Convert the value to a supported type before binding: boolean -> int 0/1, Short/Byte -> Integer, BigDecimal -> longValue()/doubleValue(), Date/Timestamp/java.time -> ISO-8601 String, UUID -> String, enum -> name().","Prefer the typed setters (setInt, setLong, setString, setDouble, setBytes) instead of setObject when the type is known.","Centralize the mapping in one helper (toSupportedSqlValue) so unsupported types fail with a clear message at the boundary.","Add a type guard that rejects unsupported classes before they reach bindObject."],"exampleFix":"// before\nps.setObject(1, Boolean.TRUE);            // throws: java.lang.Boolean\nps.setObject(2, OffsetDateTime.now());    // throws: java.time.OffsetDateTime\nps.setObject(3, BigDecimal.valueOf(\"9.99\")); // throws: java.math.BigDecimal\n\n// after\nps.setInt(1, active ? 1 : 0);\nps.setString(2, OffsetDateTime.now().toString());\nps.setDouble(3, price.doubleValue());","handlingStrategy":"type-guard","validationCode":"private static Object toSupportedSqlValue(Object x) {\n    if (x == null) return null;\n    if (x instanceof Boolean b) return b ? 1 : 0;\n    if (x instanceof Short || x instanceof Byte) return ((Number) x).intValue();\n    if (x instanceof BigDecimal bd) return bd.scale() <= 0 ? bd.longValue() : (Object) bd.doubleValue();\n    if (x instanceof java.util.Date || x instanceof java.time.temporal.Temporal)\n        return x instanceof java.sql.Timestamp t ? t : x.toString();\n    if (x instanceof UUID) return x.toString();\n    if (x instanceof Enum<?> e) return e.name();\n    return x;\n}","typeGuard":"private static boolean isSupportedBindValue(Object x) {\n    return x == null\n        || x instanceof Integer || x instanceof Long\n        || x instanceof String  || x instanceof Float\n        || x instanceof Double || x instanceof byte[];\n}","tryCatchPattern":"try {\n    stmt.bindObject(parameterIndex, x);\n} catch (SQLException e) {\n    throw new IllegalArgumentException(\n        \"unsupported bind value of type \" + (x == null ? \"null\" : x.getClass().getName()), e);\n}","preventionTips":["Route all setObject calls through one converter that whitelists supported types.","Prefer typed setters (setInt/setLong/setString/setDouble/setBytes) when the type is known.","Encode booleans as 0/1 and timestamps as ISO-8601 strings at the repository boundary.","Fail fast in unit tests by asserting isSupportedBindValue for every value you plan to bind."],"tags":["java","jdbc","setobject","type-mismatch","unsupported-type"],"backgroundTag":"unsupported-parameter-type","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}