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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 12:35:17