MapStruct无法正确将List<Integer> ids转为List<Product>的解决方法
解决MapStruct中List转List的生成代码问题
问题场景
现有Order实体、OrderPostDto,使用MapStruct做DTO到实体的映射时,期望将OrderPostDto中的productIds(List<Integer>)转换为Order中的productList(List<Product>),逻辑是通过ProductService根据ID逐个获取产品并添加到新列表。但MapStruct自动生成的代码却先调用productService.getAllProducts()获取所有产品,再追加指定ID的产品,不符合需求:
Order实体代码
@Entity @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @Table(name = "orders") public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column private int id; @Enumerated(EnumType.STRING) @Column(name = "order_status") private OrderStatus status; @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REFRESH}) @JoinTable(name = "order_product" ,joinColumns = @JoinColumn(name = "order_id") ,inverseJoinColumns = @JoinColumn(name = "product_id")) private List<Product> productList; @ManyToOne @JoinColumn(name = "user_id") private User user; @Column(name = "ordered_at") private LocalDateTime orderTime; @OneToOne @JoinTable(name = "order_payment" ,joinColumns = @JoinColumn(name = "order_id",referencedColumnName = "id") ,inverseJoinColumns = @JoinColumn(name = "payment_id", referencedColumnName = "id")) private Payment payment; @ManyToOne @JoinColumn(name = "shop_id") private Shop shop; // 构造器、getter、setter省略 }
OrderPostDto代码
public class OrderPostDto { private int id; private OrderStatus status; private int userId; private LocalDateTime orderTime; private List<Integer> productIds; private int shopId; // 构造器、getter、setter省略 }
原OrderMapper代码
@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR, uses = {ProductService.class, ShopService.class, UserService.class}) public interface OrderMapper { OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class); OrderDto orderToDto(Order order); @Mapping(source = "userId", target = "user") @Mapping(source = "productIds", target = "productList") @Mapping(source = "shopId", target = "shop") Order dtoToOrder(OrderPostDto dto); }
MapStruct生成的错误代码
protected List<Product> integerListToProductList(List<Integer> list) { if ( list == null ) { return null; } List<Product> list1 = productService.getAllProducts(); for ( Integer integer : list ) { list1.add( productService.getProductById( integer.intValue() ) ); } return list1; }
我们需要生成的代码是创建空列表再添加对应产品:
List<Product> list1 = new ArrayList<>(list.size());
解决方案
方案一:自定义单个ID转Product的方法并指定
在OrderMapper中定义明确的单个Integer转Product的方法,用@Named标记,然后在映射时指定使用该方法,让MapStruct按我们的逻辑生成列表转换代码:
@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR, uses = {ProductService.class, ShopService.class, UserService.class}) public interface OrderMapper { OrderDto orderToDto(Order order); @Mapping(source = "userId", target = "user") @Mapping(source = "productIds", target = "productList", qualifiedByName = "idToProduct") @Mapping(source = "shopId", target = "shop") Order dtoToOrder(OrderPostDto dto); @Named("idToProduct") default Product idToProduct(Integer productId, @Context ProductService productService) { return productId != null ? productService.getProductById(productId) : null; } }
这样MapStruct会自动遍历productIds,逐个调用idToProduct方法获取产品,并添加到新创建的空ArrayList中,不会再调用getAllProducts()。
方案二:直接自定义List转换方法
如果不想拆分单个元素的转换,也可以直接在OrderMapper中定义完整的List<Integer>转List<Product>的方法,MapStruct会优先使用这个自定义方法,替代默认生成的逻辑:
@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR, uses = {ProductService.class, ShopService.class, UserService.class}) public interface OrderMapper { OrderDto orderToDto(Order order); @Mapping(source = "userId", target = "user") @Mapping(source = "shopId", target = "shop") Order dtoToOrder(OrderPostDto dto); default List<Product> productIdsToProductList(List<Integer> productIds, ProductService productService) { if (productIds == null) { return null; } List<Product> productList = new ArrayList<>(productIds.size()); for (Integer id : productIds) { productList.add(productService.getProductById(id)); } return productList; } }
这里不需要在@Mapping中指定productIds到productList的映射,MapStruct会自动匹配这个自定义的List转换方法。
内容的提问来源于stack exchange,提问作者Asekeeewka
相关产品推荐
相关产品推荐

