Native Image 给 boolean 字段赋了 Integer,先区分 JDBC 读取与实体映射
GraalVM 中出现 Can not set boolean field to Integer,错误位置是反射赋值,不能据此断定 pgJDBC 返回了整数。先在同一镜像直接读取 SELECT true。
应用在 JVM 下正常,打成 GraalVM Native Image 后报 Can not set boolean field ... to java.lang.Integer。这条信息说明某次实体字段赋值收到了整数,但还不能证明数据库驱动的 ResultSet.getObject() 返回了整数。
明确出现过这一现象的组合是 pgJDBC 42.7.9、Spring Boot 与 Spring Data JDBC 4.0.2、GraalVM 25.0.2。错误发生在 Spring Data JDBC 的反射赋值处,缺少直接读取驱动的最小复现,因此不能把“GraalVM 丢掉了布尔转换路径”写成确定根因。
在同一个 Native Image 里直接读一次
在隔离测试入口中,复用已按原策略建立的 JDBC 连接,绕过实体映射做最小读取:
try (java.sql.Statement stmt = conn.createStatement();
java.sql.ResultSet rs = stmt.executeQuery("SELECT true")) {
if (rs.next()) {
Object value = rs.getObject(1);
System.out.println(value == null ? "null" : value.getClass().getName());
System.out.println(rs.getMetaData().getColumnType(1));
}
}
conn 为已有连接,不在片段中写死凭据。诊断需要编进实际使用相同依赖的 Native Image;仅在 JVM 跑通,无法说明原生镜像中的边界。
42.7.9 的 PostgreSQL bool 读取路径虽然报告 JDBC Types.BIT,但对 bool 的 OID 会直接调用 getBoolean(),返回装箱的 Boolean。JDBC 元数据中的 BIT 不等于本次值就是 Integer,不能只根据列类型码修改驱动。
根据原始返回值继续分支
如果直接 SELECT true 返回 java.lang.Boolean,再对实际失败 SQL 及对应列做相同检查。实际投影可能是 CASE、数字表达式、别名覆盖,或与实体映射预期不同的列;先取得真实值类型,再查转换器和映射链路。
若实际列在直接读取时也是 Boolean,继续定位从 ResultSet 到实体字段之间的转换。保留失败字段、列名、生成 SQL 和已有 converter 配置,避免只给反射配置增加宽泛规则。
若同一原生镜像中直接读取 SELECT true 就得到 Integer,保存依赖版本、原生构建参数与最小程序,再比较 JVM 结果。这才是指向驱动或原生构建行为的更强证据,不要用顶层实体异常代替它。
不要先全局注册 Integer -> Boolean 转换器。它可能把业务本来不该接受的数值都当真值,也掩盖错误列映射。只有确认某个边界的真实输入与业务语义后,才在相应范围选择转换。
验收回到原失败实体,覆盖 true、false 和允许的 SQL NULL。除了异常消失,还要检查字段值正确、可空性未被改写;恢复诊断前配置并保留必要日志,避免把测试输出长期留在生产请求路径。


