MapStruct映射嵌套实体时ignore配置失效触发编译报错
MapStruct编译阶段嵌套属性映射报错排查
你编写的GroupMapper映射配置如下:
@Mapper(componentModel = "spring", uses = { GroupResolver.class }, unmappedTargetPolicy = ReportingPolicy.IGNORE, unmappedSourcePolicy = ReportingPolicy.IGNORE) public abstract class GroupMapper { @Autowired private UserMapper userMapper; @Autowired private ChainMapper chainMapper; @Mapping(target = "id", source = "id") @Mapping(target = "name", source = "name") @Mapping(target = "chains", expression = "java(mapChain(group))") @Mapping(target = "users", expression = "java(mapUsers(group))") public abstract GroupResp toModel(final Group group); public Set<ChainResp> mapChain(final Group group) { return chainMapper.toModelSet(group.getChains()); } public Set<UserResp> mapUsers(final Group group) { return userMapper.toModelSet(group.getUsers()); } @Mapping(target = "id", source = "id") @Mapping(target = "name", source = "name") @Mapping(target = "chains", ignore = true) @Mapping(target = "users", ignore = true) @Mapping(target = "users.chainUnixPaths" , ignore = true ) public abstract Group toEntity(final GroupResp groupeResp); public Set<Chain> mapChains(final GroupResp groupeResp) { return chainMapper.toEntitySet(groupeResp.getChains()); } public Set<User> mapUsers(final GroupResp groupeResp) { return userMapper.toEntitySet(groupeResp.getUsers()); } }
编译阶段抛出两个错误:
No target bean properties found: can't map Collection element "UnixPathResp users[].chainUnixPaths" to "UnixPath users[].chainUnixPaths". Consider to declare/implement a mapping method: "UnixPath map(UnixPathResp value)".
No target bean properties found: can't map property "ServerResp users[].server" to "Server users[].server". Consider to declare/implement a mapping method: "Server map(ServerResp value)".
关联类定义如下:
- Group实体类
@Entity @Table(name = "groups") public class Group implements Serializable { private static final long serialVersionUID = 6980925916410978160L; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GROUPS") @SequenceGenerator(name = "SEQ_GROUPS", sequenceName = "SEQ_GROUPS") @Column(name = "GROUP_ID") private Long id; @Column(name = "GROUP_NAME", length = 256, nullable = false) private String name; @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "CHAIN_GROUP", joinColumns = @JoinColumn(name = "GROUP_ID"), inverseJoinColumns = @JoinColumn(name = "CHAIN_ID")) private Set<Chain> chains = new HashSet<>(); @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "USER_GROUP", joinColumns = @JoinColumn(name = "GROUP_ID"), inverseJoinColumns = @JoinColumn(name = "USER_ID")) private Set<User> users = new HashSet<>(); }
- GroupResp响应DTO
public class GroupResp implements Serializable{ private static final long serialVersionUID = 7184268214689299357L; @JsonProperty("GROUP_ID") private Long id; @NotBlank @JsonProperty("GROUP_NAME") private String name; @JsonProperty("CHAIN_GROUP") private Set<ChainResp> chains = new HashSet<>(); @JsonProperty("USER_GROUP") private Set<UserResp> users = new HashSet<>(); }
- 自定义GroupResolver解析器
@Component public class GroupResolver extends GenericPFResolveContract<GroupResp, Group, Long> { @Override public Long getIdof(GroupResp s) { return s.getId(); } @Override @ObjectFactory public Group resolve(GroupResp s,@TargetType Class<Group> ts) throws InstantiationException, IllegalAccessException { return super.resolve(s, ts); } }
- 解析器基类
@Component public abstract class GenericPFResolveContract<S,T,K> implements PFResolveContract<T, S> { @Autowired protected JpaRepository<T, K> sourceRepository; @Override @ObjectFactory @Transactional public T resolve(S s,@TargetType Class<T> ts) throws InstantiationException, IllegalAccessException { if(s == null || getIdof(s) == null) { return ts.newInstance(); } return sourceRepository.findById(getIdof(s)).orElseGet(()-> { T newInstance = null; try { newInstance = ts.newInstance(); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } return newInstance; } ); } public abstract K getIdof(S s); }
问题根因
报错和GroupResolver逻辑无关,核心是以下配置错误:
- 你在
toEntity方法上配置了@Mapping(target = "users", ignore = true),MapStruct规则中,如果已经将某个集合属性标记为ignore,就不能再配置该集合内部嵌套属性的映射规则,你写的@Mapping(target = "users.chainUnixPaths" , ignore = true )属于无效配置,MapStruct在编译阶段扫描到users集合内部的chainUnixPaths、server属性时,找不到对应的类型转换方法,直接抛出编译错误。 - 你在
toEntity方法中标记了chains、users属性为ignore,但类中自定义的mapChains、mapUsers方法没有被任何映射逻辑引用,MapStruct不会自动关联这两个方法到被ignore的属性上。 - 本质问题出在UserMapper的配置上:UserMapper中缺少
UnixPathResp -> UnixPath、ServerResp -> Server的类型转换方法,就算你不在GroupMapper里ignore users属性,编译时UserMapper本身也会抛出同样的映射错误。
修复方案
按以下步骤调整即可解决:
- 删除
toEntity方法上无效的嵌套属性ignore配置,也就是删掉@Mapping(target = "users.chainUnixPaths" , ignore = true )这一行。 - 如果你确实需要在Group转GroupResp、GroupResp转Group时自动映射chains和users属性,就去掉
chains、users的ignore标记,MapStruct会自动调用你类中定义的mapChain/mapUsers、mapChains/mapUsers方法完成集合转换,不需要额外写expression表达式。 - 去UserMapper中补充缺失的两个映射方法:
// 补全UnixPath和Server的类型转换,MapStruct会自动在集合元素转换时调用 UnixPath map(UnixPathResp resp); Server map(ServerResp resp);
简单字段MapStruct会自动完成映射,不需要手写赋值逻辑,如果这两个类型的转换已经在其他Mapper中定义,直接把对应Mapper加到当前@Mapper的uses参数列表里即可,不需要重复写方法。
- 如果确实不需要在GroupResp转Group实体时映射users、chains属性,只保留这两个属性的ignore标记即可,不需要额外处理嵌套属性,MapStruct会直接跳过整个被ignore的属性,不会扫描其内部字段。
内容的提问来源于stack exchange,提问作者Mohammed Housseyn Taleb
相关产品推荐
相关产品推荐

