MapStruct映射器中ObjectFactory方法未识别问题排查
MapStruct抽象类映射报错:无法识别@ObjectFactory工厂方法
背景代码
单表继承的抽象实体类Hierarchy
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING) @DiscriminatorOptions(insert = false) public abstract class Hierarchy implements Serializable { private HierarchyId id; protected Hierarchy() { } protected Hierarchy(final HierarchyId id) { this.id = id; } @EmbeddedId public HierarchyId getId() { return id; } public void setId(final HierarchyId id) { this.id = id; } @Embeddable public static class HierarchyId implements Serializable { private User parent; private User child; private String type; public HierarchyId() { } public HierarchyId(final User parent, final User child, final String type) { this.parent = parent; this.child = child; this.type = type; } @ManyToOne(fetch = FetchType.LAZY) public User getParent() { return parent; } public void setParent(final User parent) { this.parent = parent; } @ManyToOne(fetch = FetchType.LAZY) public User getChild() { return child; } public void setChild(final User child) { this.child = child; } @Column(name = "type", nullable = false, length = 1) public String getType() { return type; } public void setType(final String type) { this.type = type; } } }
自定义的MapStruct映射器HierarchyMapper
@Configuration @Mapper public abstract class HierarchyMapper { @Autowired private UserService userService; @Mapping(target = "id.parent.id", ignore = true) @Mapping(target = "id.child.id", ignore = true) @Mapping(source = "type", target = "id.type") @BeanMapping(qualifiedByName = "afterHierarchyMapping") public abstract Hierarchy mapHierarchy(HierarchyDto hierarchy); @ObjectFactory public Hierarchy createHierarchy(HierarchyDto hierarchy) { if (SUBTYPE_A.equals(hierarchy.getType())) { return new SubtypeA(); } else if (SUBTYPE_B.equals(hierarchy.getType())) { return new SubtypeB(); } return null; } @AfterMapping @Named("afterHierarchyMapping") void afterHierarchyMapping(@MappingTarget Hierarchy hierarchy, HierarchyDto hierarchyDto) { hierarchy.getId() .setParent(userService.getUserById(hierarchyDto.getIdParent())); hierarchy.getId() .setChild(userService.getUserById(hierarchyDto.getIdChild())); } }
报错信息
java: The return type Hierarchy is an abstract class or interface. Provide a non abstract / non interface result type or a factory method.
移除@BeanMapping注解后,会触发User抽象类的相同报错。
问题原因与修复方案
1. 核心原因:映射器未配置Spring组件模型
你的@Mapper注解缺少componentModel = "spring"配置,MapStruct默认采用default组件模型,不会将映射器作为Spring Bean处理,导致@ObjectFactory方法无法被正确关联和调用。
2. 修复步骤
步骤1:修正映射器的@Mapper配置
添加componentModel = "spring",确保MapStruct生成Spring兼容的实现类,同时识别@Autowired和@ObjectFactory:
@Configuration @Mapper(componentModel = "spring") // 新增Spring组件模型配置 public abstract class HierarchyMapper { @Autowired private UserService userService; // 调整映射规则:完全忽略parent和child的自动映射,避免MapStruct尝试实例化抽象User类 @Mapping(target = "id.parent", ignore = true) @Mapping(target = "id.child", ignore = true) @Mapping(source = "type", target = "id.type") @BeanMapping(qualifiedByName = "afterHierarchyMapping") public abstract Hierarchy mapHierarchy(HierarchyDto hierarchy); @ObjectFactory public Hierarchy createHierarchy(HierarchyDto hierarchy) { if (SUBTYPE_A.equals(hierarchy.getType())) { return new SubtypeA(); } else if (SUBTYPE_B.equals(hierarchy.getType())) { return new SubtypeB(); } // 建议抛出异常而非返回null,避免后续空指针 throw new IllegalArgumentException("不支持的层级类型: " + hierarchy.getType()); } @AfterMapping @Named("afterHierarchyMapping") void afterHierarchyMapping(@MappingTarget Hierarchy hierarchy, HierarchyDto hierarchyDto) { hierarchy.getId().setParent(userService.getUserById(hierarchyDto.getIdParent())); hierarchy.getId().setChild(userService.getUserById(hierarchyDto.getIdChild())); } }
步骤2:确保子类提供无参构造器
SubtypeA和SubtypeB必须包含无参构造器(可以是protected),因为MapStruct创建实例后会通过setter填充属性:
@Entity @DiscriminatorValue("A") public class SubtypeA extends Hierarchy { protected SubtypeA() { super(); } }
步骤3:彻底忽略User字段的自动映射
之前只忽略了id.parent.id和id.child.id,但MapStruct仍会尝试映射User对象本身。改为忽略id.parent和id.child,完全交由@AfterMapping通过userService获取实例,避免触发User抽象类的实例化报错。
3. 验证方法
执行项目清理编译(如mvn clean compile),查看MapStruct生成的HierarchyMapperImpl类,确认:
- 先调用
createHierarchy方法获取具体子类实例 - 执行完基础映射后调用
afterHierarchyMapping方法
内容的提问来源于stack exchange,提问作者gb2
相关产品推荐
相关产品推荐

