英文:
Map Nested elements - Mapstruct
问题
我正试图使用MapStruct将以下源类映射到目标类。
目标类:
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>();
}
源类:
public class UserList {
protected List<User> user;
}
public class User {
protected String userId;
protected List<String> productRefId; //该特定用户的产品列表
}
public class ProductList {
protected List<Product> product;
}
public class Product {
protected String productId; //对productRefId的引用
protected String productName;
protected List<Details> productDetails;
}
映射器接口:
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);
我的问题是,我想要将 CustProduct 连接到 Customer。
为此,我尝试了像下面这样的 AfterMapping:
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));
// 在此处设置 custProduct 对象的 productName 和 productDetails(通过迭代 ProductList 并从 Product 中获取)
custProducts.add(custProduct);
}
customer.setCustProducts(custProducts);
}
有人能否请帮忙填写上面的注释部分?
或者是否有其他选项可以映射这些对象?
编辑:我尝试了下面的解决方案,但接口实现类本身发生了变化。
英文:
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.
答案1
得分: 5
你需要使用@Context注解将ProductList对象带入上下文。
将映射器方法更改为以下定义,并在调用mapUser
时传递ProductList对象:
@Mappings({
@Mapping(target = "customerId", source = "paxJourneyType.paxJourneyID"),
@Mapping(target = "products", ignore = true)
})
Customer mapUser(User user, @Context ProductList productList);
然后您可以在@AfterMapping
方法中使用相同的ProductList对象:
default void findProducts(User user, @Context ProductList productList, @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));
Product product = getProduct(productList, productIds.get(i));
custProduct.setCustPdtName(product.getProductName());
custProducts.add(custProduct);
}
customer.setCustProducts(custProducts);
}
private Product getProduct(ProductList productList, String productId) {
//在ProductList中进行迭代并从中获取Product
}
英文:
You need to use @Context annotation to bring ProductList object into the context.
Change the mapper method to below definition and pass ProductList object when calling mapUser
:
@Mappings({
@Mapping(target = "customerId", source = "paxJourneyType.paxJourneyID”),
@Mapping(target = "products", ignore = true)
})
Customer mapUser(User user, @Context ProductList productList);
and then you can use the same ProductList object in @AfterMapping
method :
default void findProducts(User user, @Context ProductList productList @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));
Product product = getProduct(ProductList productList,productIds.get(i));
custProduct.setCustPdtName(product.getProductName);
custProducts.add(custProduct);
}
}
customer.setCustProducts(custProducts);
}
private Product getProduct(ProductList productList,String productId){
//Iterate through ProductList and get from Product
}
答案2
得分: 3
你可以在没有使用 `@AfterMapping` 的情况下完成,但是你需要稍微帮助 MapStruct:
```java
@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);
}
或者,你可以手动迭代 productRefIds
:
@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);
}
在这两种情况下,你都需要以某种方式处理 productId
在 productsMap
中不存在的情况。
不使用 @AfterMapping
的优点是目标类可以是不可变的。
<details>
<summary>英文:</summary>
You can do it without `@AfterMapping` but you will need to help MapStruct a little bit:
```java
@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.
答案3
得分: 0
你的 @AfterMapping 方法不起作用,因为 @MappingTarget 应该是 builder 类型的。
@AfterMapping
default void findProducts(User user, @MappingTarget Customer.CustomerBuilder customer) {
...
}
英文:
Your @AfterMapping method doesn't works because the @MappingTarget should be of builder type
@AfterMapping
default void findProducts(User user, @MappingTarget Customer.CustomerBuilder customer) {
...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论