Jooq Records.mapping遇多构造函数类无法识别构造器的问题咨询
问题背景
用jOOQ代码生成器生成的POJO类会包含多个构造函数(默认构造器、接口构造器、字段构造器),示例代码如下:
public class ProductLang implements IProductLang { ... public ProductLang() {} public ProductLang(IProductLang value) { this.productId = value.getProductId(); this.langId = value.getLangId(); this.name = value.getName(); this.description = value.getDescription(); } public ProductLang( Long productId, Integer langId, String name, String description ) { this.productId = productId; this.langId = langId; this.name = name; this.description = description; } ... }
当在临时转换器(ad-hoc-converters)中使用RecordMapping API的Records.mapping时,无法匹配到正确的构造函数,报错示例:
RecordMapper<Record4<Long, Integer, String, String>, ProductLang> r = Records.mapping(ProductLang::new);
报错信息:Cannot resolve constructor 'ProductLang'
删掉默认构造器和接口构造器后,错误消失,能正常识别字段构造器。这个问题在jOOQ DSL查询的convertFrom函数里用Records.mapping时也会复现:
... multiset( selectDistinct( PRODUCT_LANG.PRODUCTID, PRODUCT_LANG.LANGID, PRODUCT_LANG.NAME, PRODUCT_LANG.DESCRIPTION ) .from(PRODUCT_LANG) .where(PRODUCT_LANG.PRODUCTID.eq(PRODUCT.PRODUCTID)) ).convertFrom(r -> r.map(Records.mapping(ProductLangDTO::new))) ...
咨询以下问题:
Records.mapping是否支持多构造函数的类?- 若支持,需要做哪些配置才能正常使用?
- 若不支持,针对这类多构造函数的类,推荐的Record映射方式是什么?
解答
Records.mapping支持多构造函数类,但存在重载解析限制Records.mapping依赖Java的方法引用重载解析机制,当类中有多个构造函数时,编译器无法自动推断出要匹配的目标构造函数——即便其他构造函数的参数特征和目标构造器差异明显,编译器仍可能无法完成精准匹配,从而抛出构造函数无法解析的错误。解决配置/写法调整方案
有两种方式可以让编译器正确识别目标构造函数:
- 显式指定构造函数调用逻辑:用Lambda表达式代替方法引用,直接明确调用目标构造函数,绕过重载歧义:
RecordMapper<Record4<Long, Integer, String, String>, ProductLang> r = Records.mapping((Long pId, Integer lId, String n, String d) -> new ProductLang(pId, lId, n, d)); - 修改jOOQ代码生成配置:在生成POJO时去掉不需要的构造函数,仅保留字段构造器。在jOOQ的代码生成XML配置中,可通过
<pojoConstructors>节点精准控制:
生成后的POJO仅保留字段构造器,<generator> <database>...</database> <generate> <pojos>true</pojos> <pojoConstructors> <defaultConstructor>false</defaultConstructor> <interfaceConstructor>false</interfaceConstructor> <fieldConstructor>true</fieldConstructor> </pojoConstructors> </generate> </generator>Records.mapping(ProductLang::new)即可正常工作。
- 替代映射方案(需保留多构造函数时)
如果必须保留多个构造函数,除了上述Lambda写法,还可以使用以下两种映射方式:
- 使用
Record.into(Class)方法:jOOQ会自动根据字段名匹配POJO属性完成映射(需保证属性名与字段名一致,或配置正确的映射注解):RecordMapper<Record4<Long, Integer, String, String>, ProductLang> r = record -> record.into(ProductLang.class); - 手动映射:完全自主控制字段到POJO属性的赋值,适合映射关系复杂的场景:
RecordMapper<Record4<Long, Integer, String, String>, ProductLang> r = record -> { ProductLang pl = new ProductLang(); pl.setProductId(record.value1()); pl.setLangId(record.value2()); pl.setName(record.value3()); pl.setDescription(record.value4()); return pl; };
内容的提问来源于stack exchange,提问作者funkrusher
相关产品推荐
相关产品推荐

