JOOQ动态查询中自定义布尔类型绑定未触发问题排查
问题分析与解决
问题背景
为适配Oracle中存储"true"/"false"的VARCHAR2(6)列,实现了自定义布尔类型转换器CustomBooleanConverter和绑定CustomBooleanBinding,并通过Maven的forcedType配置关联到AMENDABLE字段。生成的实体类字段已正确绑定该自定义逻辑,但在动态构建查询时,外层查询对别名表的AMENDABLE字段添加=true条件,生成的SQL将true转为1,未触发自定义绑定导致执行失败;而将条件放在内层子查询时则正常工作。
问题代码复现
自定义转换器
public class CustomBooleanConverter implements Converter<String, Boolean>{ @Override public Boolean from(String s) { if (s == null) { return null; } return s.equals("true"); } @Override public String to(Boolean aBoolean) { if (aBoolean == null) { return null; } return aBoolean.booleanValue() ? "true" : "false"; } @Override public Class<String> fromType() { return String.class; } @Override public Class<Boolean> toType() { return Boolean.class; } }
自定义绑定类
public class CustomBooleanBinding implements Binding<String, Boolean> { @Override public Converter<String, Boolean> converter() { return new CustomBooleanConverter(); } @Override public void sql(BindingSQLContext<Boolean> bindingSQLContext) throws SQLException { String converted = converter().to(bindingSQLContext.value()); if (bindingSQLContext.render().paramType() == ParamType.INLINED){ if (converted == null) { bindingSQLContext.render().sql("NULL"); } else { bindingSQLContext.render().sql("\'"+converted+"\'"); } } else { bindingSQLContext.render().sql(bindingSQLContext.variable()); } } @Override public void register(BindingRegisterContext<Boolean> bindingRegisterContext) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public void set(BindingSetStatementContext<Boolean> bindingSetStatementContext) throws SQLException { String value = bindingSetStatementContext.convert(converter()).value(); bindingSetStatementContext.statement().setString(bindingSetStatementContext.index(), value == null ? null : value); } @Override public void set(BindingSetSQLOutputContext<Boolean> bindingSetSQLOutputContext) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public void get(BindingGetResultSetContext<Boolean> bindingGetResultSetContext) throws SQLException { bindingGetResultSetContext.convert(converter()) .value(bindingGetResultSetContext.resultSet().getString(bindingGetResultSetContext.index())); } @Override public void get(BindingGetStatementContext<Boolean> bindingGetStatementContext) throws SQLException { bindingGetStatementContext.convert(converter()); } @Override public void get(BindingGetSQLInputContext<Boolean> bindingGetSQLInputContext) throws SQLException { throw new SQLFeatureNotSupportedException(); } }
Maven配置
<forcedType> <userType>java.lang.Boolean</userType> <binding>com.jooq.config.CustomBooleanBinding</binding> <includeExpression>.*\.AMENDABLE</includeExpression> </forcedType>
生成的字段代码
/** * The column <code>TABLEXX.AMENDABLE</code>. */ public final TableField<TableXXRecord, Boolean> AMENDABLE = createField(DSL.name("AMENDABLE"), SQLDataType.VARCHAR(6), this, "", new CustomBooleanBinding());
出错的动态查询代码
SelectConditionStep subquery= select(tableXX.Other_column, tableXX.amendable ).from(tableXX); Table<?> table = subquery.asTable(); SelectWhereStep<?> query = selectFrom(table); query.where(table.field("OTHER_COLUM", String.class).equal("0005698")); query.where(table.field("AMENDABLE", Boolean.class).equal(true));
生成的错误SQL
select alias_90892522.OTHER COLUMN, ......, alias_90892522.AMENDABLE from ( select OTHER COLUMN, ......, AMENDABLE from tableXX ) alias_90892522 where ( "alias_90892522"."OTHER COLUMN" = '0005698' and "alias_90892522"."AMENDABLE" = 1 )
问题根源
当使用table.field("AMENDABLE", Boolean.class)从子查询的别名表中获取字段时,JOOQ无法识别该字段原本绑定的CustomBooleanBinding。别名表是动态生成的,JOOQ不会自动继承原表字段的绑定信息,而是默认使用Boolean类型对应的标准SQL转换逻辑(将布尔值转为整数1/0),因此自定义绑定未被触发。
而将条件放在内层子查询时,直接使用了生成的tableXX.AMENDABLE字段,该字段已明确关联自定义绑定,因此转换逻辑正常执行。
解决方案
方案1:复用生成的字段引用
如果动态构建查询时能获取到原表的生成字段,直接通过别名表引用该字段,保留原绑定信息:
// 直接使用生成的AMENDABLE字段,通过别名表关联 query.where(table.field(tableXX.AMENDABLE).equal(true));
方案2:手动为动态字段绑定自定义Binding
若必须通过字段名动态查找,获取字段后手动指定绑定:
Field<Boolean> amendableField = table.field("AMENDABLE", Boolean.class) .bind(new CustomBooleanBinding()); query.where(amendableField.equal(true));
方案3:全局配置Converter(替代Binding)
若不需要Binding的高级功能,改用全局Converter配置,让JOOQ自动应用转换逻辑:
- 修改Maven的
forcedType配置,替换binding为converter:
<forcedType> <userType>java.lang.Boolean</userType> <converter>com.jooq.config.CustomBooleanConverter</converter> <includeExpression>.*\.AMENDABLE</includeExpression> </forcedType>
- 移除自定义Binding类,仅保留Converter即可。
内容的提问来源于stack exchange,提问作者Julian Quintanilla
相关产品推荐
相关产品推荐

