{"record":{"id":"e171a64085ab77e6","repo":"tursodatabase/turso","slug":"unsupported-object-type-in-bindobject-classname","errorCode":null,"errorMessage":"Unsupported object type in bindObject: {className}","messagePattern":"Unsupported object type in bindObject: (.+?)","errorType":"exception","errorClass":"java.sql.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/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/core/TursoStatement.java#L222-L258","documentation":"bindObject dispatches on exact runtime types and only accepts null, Byte, Short, Integer, Long, String, Float, Double, and byte[]; every other class falls through to this throw with the class name appended. There is no widening or coercion, so Boolean, Character, BigDecimal, java.util.Date, java.time types, enums, and UUID all fail even though they feel 'bindable'. This is the backing of setObject-style JDBC APIs.","triggerScenarios":"Calling stmt.bindObject(i, x) / setObject with Boolean.TRUE, a BigDecimal, a LocalDate or java.util.Date, a Character, a UUID, or any domain object; receiving untyped values (Map<String,Object> from JSON deserialization) and forwarding them directly.","commonSituations":"Generic persistence layers that pass through whatever the JSON deserializer produced; DTOs with BigDecimal amounts or boolean flags; ports of code from drivers that auto-convert more types.","solutions":["Convert before binding: boolean -> 0/1 Integer, BigDecimal -> long/double or text, temporal -> ISO-8601 String or epoch Long, Character -> String, UUID -> String","Add your own dispatch helper that maps your domain types onto the supported set","For untyped data, normalize values at the boundary (right after deserialization) rather than at bind time"],"exampleFix":"// before\nstmt.bindObject(1, activeFlag);          // Boolean -> throws\nstmt.bindObject(2, amount);              // BigDecimal -> throws\n\n// after\nstmt.bindObject(1, activeFlag ? 1 : 0);              // boolean as Integer\nstmt.bindObject(2, amount.longValueExact());         // or toPlainString() for text","handlingStrategy":"type-guard","validationCode":"Object x = value;\nif (!isSupportedBindValue(x)) {\n  x = convertForBind(x); // your mapping for Boolean, BigDecimal, temporal, UUID, ...\n}\nstmt.bindObject(1, x);","typeGuard":"static boolean isSupportedBindValue(Object x) {\n  return x == null\n      || x instanceof Byte\n      || x instanceof Short\n      || x instanceof Integer\n      || x instanceof Long\n      || x instanceof String\n      || x instanceof Float\n      || x instanceof Double\n      || x instanceof byte[];\n}","tryCatchPattern":"try {\n  stmt.bindObject(i, x);\n} catch (SQLException e) {\n  throw new IllegalArgumentException(\n      \"unsupported bind type \" + x.getClass().getName(), e);\n}","preventionTips":["Convert at the boundary: boolean -> 0/1, BigDecimal -> long/double/text, temporal -> ISO text or epoch long, Character/UUID -> String","Cover every type your DTOs expose in unit tests of the conversion helper","The dispatch is exact instanceof — subtypes and autoboxing tricks beyond the nine supported forms fail","Normalize Map<String,Object> values right after JSON deserialization, not at bind time"],"tags":["java","jdbc","prepared-statement","type-mapping","setobject"],"backgroundTag":"unsupported-parameter-type","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}