Reputation: 340
I am getting a list of objects from 3rd party but it will always contain one object only. So at my end in target I have created it as an object rather than list. That object contains multiple lists inside it just like source object.
This is how I am trying to map a list to an object. ChargeTransaction contain orderInvoice as an object and not a list. For list which are inside ChargeTransaction I have created separate mappers. I dont want to write java code in @afterMapping because then how nested lists will be mapped. The nested lists are of type in both the objects.
@Mapping(target = "orderInvoice", source = "basePaymentRequest.invoice.eventPayload.orderInvoices")
ChargeTransaction createInvoiceCTMapper(PaymentTriggerBaseModel basePaymentRequest, ChargeType chargeType);
Error
java: Can't map property "List<OrderInvoice> basePaymentRequest.invoice.eventPayload.orderInvoices" to "OrderInvoice orderInvoice". Consider to declare/implement a mapping method: "OrderInvoice map(List<OrderInvoice> value)".
I tried
@Mapping(target = "orderInvoice", expression= "java(basePaymentRequest.invoice.eventPayload.orderInvoices.get(0))")
But it gives error in Impl class
chargeTransaction.setOrderInvoice( basePaymentRequest.invoice.eventPayload.orderInvoices.get(0) );
java: incompatible types: com.sams.oms.ng.common.models.payment.request.OrderInvoice cannot be converted to com.sams.oms.ng.common.models.payment.cosmos.OrderInvoice
Upvotes: 1
Views: 13313
Reputation: 1
The first answer provided is correct, but you do not need to use the qualifiedByName attribute and @Named annotation in this case. Mapstruct is smart enough to pick up your method itself if there is only one possible candidate to map a collection of OrderInvoice to one single OrderInvoice.
I prefer to leave those out to make the code a bit cleaner.
In general, you typically only need qualifiedByName when you overwrite a standard mapstruct conversion (like String to String, but your custom function isn't a straight copy) or when multiple conversions of the same type exist.
The 2nd answer is risky, as there are no null checks and any of those "get" calls could result in a null being returned and then doing a get on that will result in NPE.
Upvotes: 0
Reputation: 24
If we are mapping with the Java expression we need to add get
and ()
in the expression like below.
@Mapping(target = "orderInvoice", expression= "java(basePaymentRequest.getInvoice().getEventPayload().getOrderInvoices().get(0))")
Upvotes: 0
Reputation: 18403
IMHO the best way to solve this problem is to use a @Named
paired with @Mapping#qualifiedByName
@Mapper
class Mapper {
@Mapping(target = "orderInvoice", source ="basePaymentRequest.invoice.eventPayload.orderInvoices", qualifiedByName="firstElement")
ChargeTransaction createInvoiceCTMapper(PaymentTriggerBaseModel basePaymentRequest, ChargeType chargeType);
@Named("firstElement")
OrderInvoice map(List<OrderInvoice> value) {
if(value == null) return null;
if(value.isEmpty()) return null;
return map(value.get(0));
}
abstract com.sams.oms.ng.common.models.payment.request.OrderInvoice map(com.sams.oms.ng.common.models.payment.cosmos.OrderInvoice invoice);
}
In this way you are instructed MapStruct to use map(List<>)
to convert invoices to a single OrderInvoice and abstract map(OrderInvoice)
to let MapStruct autogenerate mapping code.
Code in untested because I haven't limited spare time today,but I hope my example may be useful;if anything is wrong feel free to comment and I will correct code asap.
Upvotes: 3