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

如何将jOOQ查询结果映射到Immutables不可变对象?

解决jOOQ映射Immutables可空Optional字段的问题

当用Immutables生成带Optional可空字段的对象时,jOOQ默认会把数据库NULL值直接传入of()工厂方法,但该方法要求传入Optional.empty()而非null,导致映射失败。以下是几种可行的解决办法:

方法一:配置Immutables生成支持null参数的工厂方法

通过Immutables的@Value.Style注解开启nullAccepted选项,让生成的of()方法允许接收null参数,并自动将其转换为Optional.empty()。

示例代码:

@Value.Immutable
@Value.Style(
    factory = "of", // 指定工厂方法名保持为of
    nullAccepted = true // 允许参数为null,内部自动处理为Optional.empty()
)
public abstract class User {
    public abstract String firstName();
    @Nullable // 标记该字段可为null
    public abstract Optional<String> lastName();
}

这样jOOQ在映射时,遇到数据库中的NULL值直接传入of()方法即可,Immutables会自动把null转为Optional.empty(),无需额外处理。

方法二:给jOOQ注册全局Optional转换器

自定义一个Converter,让jOOQ在映射时自动将数据库的NULL值转换为Optional.empty(),非NULL值转为Optional.of(值),适配Immutables的of()方法要求。

示例代码:

// 通用Optional转换器
public class OptionalConverter<T> implements Converter<T, Optional<T>> {
    private final Class<T> type;

    public OptionalConverter(Class<T> type) {
        this.type = type;
    }

    @Override
    public Optional<T> from(T databaseValue) {
        return Optional.ofNullable(databaseValue);
    }

    @Override
    public T to(Optional<T> domainValue) {
        return domainValue.orElse(null);
    }

    @Override
    public Class<T> fromType() {
        return type;
    }

    @Override
    public Class<Optional<T>> toType() {
        return (Class<Optional<T>>) (Class<?>) Optional.class;
    }
}

// 注册到jOOQ配置
Configuration jooqConfig = new DefaultConfiguration()
    .set(SQLDialect.YOUR_DIALECT) // 替换为你的数据库方言,比如MYSQL、POSTGRES
    .set(new DefaultDataTypeProvider() {
        @Override
        public <T> DataType<T> defaultDataType(Class<T> type) {
            // 针对String类型的Optional注册转换器,可按需添加其他类型(如Integer、Long等)
            if (type.equals(Optional.class)) {
                return (DataType<T>) SQLDataType.VARCHAR.asConvertedDataType(new OptionalConverter<>(String.class));
            }
            return super.defaultDataType(type);
        }
    });

注册后,jOOQ在映射到Optional类型字段时会自动转换null值,完美适配Immutables的of()方法。

方法三:自定义jOOQ RecordMapper

如果以上两种方法不适用,可以自定义RecordMapper,手动处理字段映射,将null值转为Optional.empty()后再调用Immutables的of()方法。

示例代码:

public class UserRecordMapper implements RecordMapper<Record, ImmutableUser> {
    @Override
    public ImmutableUser map(Record record) {
        String firstName = record.get("first_name", String.class);
        String lastName = record.get("last_name", String.class);
        // 手动将null转为Optional.empty()
        return ImmutableUser.of(firstName, Optional.ofNullable(lastName));
    }
}

// 使用时指定Mapper
Result<Record> result = dslContext.select().from("user").fetch();
List<ImmutableUser> users = result.map(new UserRecordMapper());

这种方法需要为每个Immutables对象编写单独的Mapper,适合字段较少的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 13:17:47