You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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自动应用转换逻辑:

  1. 修改Maven的forcedType配置,替换binding为converter:
<forcedType>
    <userType>java.lang.Boolean</userType>
    <converter>com.jooq.config.CustomBooleanConverter</converter>                                                    
    <includeExpression>.*\.AMENDABLE</includeExpression>
</forcedType>
  1. 移除自定义Binding类,仅保留Converter即可。

内容的提问来源于stack exchange,提问作者Julian Quintanilla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 09:14:53