I'm trying to map following source classes to target class using MapStruct.
Target Classes :
public class Response {
private List<Customer> customer = new ArrayList<Customer>();
}
public class Customer {
private String customerId;
private List<Product> products = new ArrayList<Product>();
}
public class CustProduct {
private String CustProductId;
private String CustPdtName;
private List<productDetail> CustProductDetails = new ArrayList<productDetail>();
}
Source Classes :
public class UserList {
protected List<User> user;
}
public class User {
protected String userId;
protected List<String> productRefId; //List of products for that particular user
}
public class ProductList {
protected List<Product> product;
}
public class Product {
protected String productId; //Reference to productRefId
protected String productName;
protected List<Details> productDetails;
}
Mapper Interface :
List<Customer> mapUser(List<User> user);
@Mappings({
@Mapping(target = "customerId", source = "userId”),
@Mapping(target = "products", ignore = true)
})
Customer mapUser(User user);
@Mappings({
@Mapping(target = "CustProductId", source = "productId"),
@Mapping(target = "CustPdtName", source = "productName"),
@Mapping(target = "CustProductDetails", source = "productDetails")
})
CustProduct mapUser(Product product);
My problem is, I want to connect CustProduct with Customer For that, I tried AfterMapping like :
default void findProducts(User user, @MappingTarget Customer customer) {
List<String> productIds = user.getproductRefId();
List<CustProduct> custProducts = new ArrayList<>();
for(int i=0; i<productIds.size();i++){
CustProduct custProduct = new CustProduct();
custProduct.setCustProductId(productIds.get(i));
//Here I want set productName and productDetails to custProduct Object(Iterating through ProductList and get from Product)
custProducts.add(custProduct);
}
}
customer.setCustProducts(custProducts);
}
Can anyone please help to fill out the comment section above? Or is there any other option to map these objects?
Edited : I tried the below solution but the interface implementation class itself changed.
You can do it without @AfterMapping
but you will need to help MapStruct a little bit:
@Mapper
public interface CustMapper {
@Mapping(target = "customerId", source = "userId")
@Mapping(target = "products", source = "productRefIds")
Customer map(User user, @Context Map<String, Product> productsMap);
List<CustProduct> map(List<String> productRefIds, @Context Map<String, Product> productsMap);
default CustProduct map(String productId, @Context Map<String, Product> productsMap) {
return map(productsMap.get(productId));
}
@Mapping(target = "custProductId", source = "productId")
@Mapping(target = "custProductName", source = "productName")
@Mapping(target = "custProductDetails", source = "productDetails")
CustProduct map(Product product);
CustProductDetail map(ProductDetail productDetail);
}
alternatively, you can iterate over productRefIds
manually:
@Mapper
public interface CustMapper {
@Mapping(target = "customerId", source = "userId")
@Mapping(target = "products", source = "productRefIds")
Customer map(User user, @Context Map<String, Product> productsMap);
default List<CustProduct> map(List<String> productRefIds, @Context Map<String, Product> productsMap) {
return productRefIds.stream().map(productsMap::get).map(this::map).collect(Collectors.toList());
}
@Mapping(target = "custProductId", source = "productId")
@Mapping(target = "custProductName", source = "productName")
@Mapping(target = "custProductDetails", source = "productDetails")
CustProduct map(Product product);
CustProductDetail map(ProductDetail productDetail);
}
In both scenarios you will need to handle somehow the situation, when productId
is not present in the productsMap
.
The advantage of not using @AfterMapping
is that target classes can be immutable.