Voordat we de diepte induiken, laten we snel herhalen waar MapStruct over gaat. Het is een codegenerator die type-veilige bean mappers maakt tijdens de compileertijd. Geen runtime overhead, geen reflectie magie - gewoon pure, efficiënte Java-code. Hier is een voorbeeld van hoe een basis mapper eruitziet:
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDTO mapToDTO(User user);
}
Eenvoudig, toch? Maar oh jongen, we zijn nog maar net begonnen!
De Top 10 MapStruct Trucs Die Je Nooit Wist Dat Je Nodig Had
1. Mapping met Context: Het Geheime Ingrediënt
Heb je ooit extra informatie aan je mapper moeten doorgeven? Maak kennis met de @Context annotatie:
@Mapper
public interface UserMapper {
@Mapping(target = "role", source = "user")
UserDTO mapToDTO(User user, @Context SecurityContext securityContext);
default String mapRole(User user, @Context SecurityContext securityContext) {
return securityContext.isAdmin() ? "ADMIN" : user.getRole();
}
}
Nu kun je runtime context in je mapping logica injecteren. Handig, hè?
2. Aangepaste Methode Mappings: Wanneer Standaard Niet Voldoende Is
Soms moet je zelf aangepaste mapping logica schrijven:
@Mapper
public interface DateMapper {
@Mapping(target = "formattedDate", source = "date", qualifiedByName = "formatDate")
DateDTO map(DateEntity date);
@Named("formatDate")
default String formatDate(LocalDate date) {
return date != null ? date.format(DateTimeFormatter.ISO_LOCAL_DATE) : null;
}
}
Tip: Gebruik @Named om je aangepaste methoden georganiseerd en herbruikbaar te houden in verschillende mappers.
3. Collectie Mapping: Omdat Eén Nooit Genoeg Is
MapStruct gaat geweldig om met collecties:
@Mapper
public interface ProductMapper {
List mapToDTOList(List products);
Set mapToProductNames(List products);
}
Het past automatisch de element mapping toe op elk item in de collectie. Magisch!
4. Geneste Object Mapping: Diep Duiken
Omgaan met complexe objectstructuren? MapStruct helpt je uit de brand:
@Mapper
public interface OrderMapper {
@Mapping(target = "customerName", source = "customer.name")
@Mapping(target = "orderItems", source = "items")
OrderDTO mapToDTO(Order order);
@Mapping(target = "productName", source = "product.name")
OrderItemDTO mapToItemDTO(OrderItem item);
}
Het behandelt naadloos geneste objecten, waardoor je bespaard blijft van de nachtmerrie van handmatige mapping.
5. Voorwaardelijke Mapping: De Kunst van Beslissingen Nemen
Soms moet je tijdens het mappen beslissingen nemen:
@Mapper
public interface UserMapper {
@Mapping(target = "status", expression = "java(mapStatus(user))")
UserDTO mapToDTO(User user);
default String mapStatus(User user) {
return user.getLastLoginDate() != null &&
user.getLastLoginDate().isAfter(LocalDate.now().minusDays(30))
? "ACTIVE" : "INACTIVE";
}
}
Gebruik expressies om complexe logica in je mappings te injecteren.
6. Velden Negeren: De Kunst van Selectieve Mapping
Soms is minder meer. Negeer velden die je niet nodig hebt:
@Mapper
public interface UserMapper {
@Mapping(target = "password", ignore = true)
@Mapping(target = "createdAt", ignore = true)
UserDTO mapToDTO(User user);
}
Perfect voor wanneer je te maken hebt met gevoelige gegevens of velden die niet in je DTO thuishoren.
7. Omgekeerde Mapping: Beide Kanten Op
Moet je heen en weer mappen? MapStruct heeft je gedekt:
@Mapper
public interface UserMapper {
@Mapping(target = "id", ignore = true)
User mapToEntity(UserDTO dto);
UserDTO mapToDTO(User user);
}
Definieer gewoon beide methoden, en MapStruct zal de bidirectionele mapping voor je afhandelen.
8. Standaardwaarden: De Lege Plekken Invullen
Soms moet je standaardwaarden geven voor ontbrekende gegevens:
@Mapper
public interface ProductMapper {
@Mapping(target = "inStock", constant = "true")
@Mapping(target = "category", defaultValue = "UNCATEGORIZED")
ProductDTO mapToDTO(Product product);
}
Gebruik constant voor hardcoded waarden en defaultValue voor terugvallen wanneer de bron null is.
9. Voor en Na Mapping: De Laatste Touch
Moet je enkele bewerkingen uitvoeren voor of na de mapping? Maak kennis met @BeforeMapping en @AfterMapping:
@Mapper
public abstract class OrderMapper {
@Mapping(target = "total", ignore = true)
public abstract OrderDTO mapToDTO(Order order);
@AfterMapping
protected void calculateTotal(Order order, @MappingTarget OrderDTO orderDTO) {
orderDTO.setTotal(order.getItems().stream()
.mapToDouble(item -> item.getPrice() * item.getQuantity())
.sum());
}
}
Perfect voor complexe berekeningen of last-minute aanpassingen.
10. Aangepaste MapStruct Annotaties: De Kracht van Abstractie
Maak je eigen annotaties om veelvoorkomende mappingpatronen te kapselen:
@Retention(RetentionPolicy.CLASS)
@Mapping(target = "id", ignore = true)
@Mapping(target = "createdAt", expression = "java(java.time.LocalDateTime.now())")
public @interface ToEntity { }
@Mapper
public interface UserMapper {
@ToEntity
User mapToEntity(UserDTO dto);
}
Deze aanpak helpt je mappers schoon te houden en bevordert herbruikbaarheid in je codebase.
Afronding: De MapStruct Magie Ontketend
Daar heb je het - 10 MapStruct trucs die je Quarkus mapping naar een hoger niveau tillen. Van contextbewuste mappings tot aangepaste annotaties, MapStruct zit boordevol functies die zelfs de meest complexe objecttransformaties kunnen vereenvoudigen.
Onthoud, de sleutel tot het beheersen van MapStruct is experimenteren. Wees niet bang om in de documentatie te duiken en verschillende combinaties van deze technieken uit te proberen. Je toekomstige zelf (en je code reviewers) zullen je dankbaar zijn voor de schone, efficiënte en onderhoudbare mapping code die je zult produceren.
Dus, de volgende keer dat je jezelf betrapt op het grijpen naar die handmatige setter soep, neem een stap terug en vraag jezelf af: "Wat zou MapStruct doen?" De kans is groot dat het een truc in petto heeft die je leven een stuk makkelijker maakt.
Veel plezier met mappen, Quarkus ninja's! 🚀
"De kunst van het mappen ligt niet in het creëren van nieuwe objecten, maar in het onthullen van de relaties tussen bestaande." - Anonieme Ontwikkelaar (waarschijnlijk)
P.S. Vergeet niet de MapStruct repository op GitHub te sterren als je het nuttig vindt. Open source projecten gedijen op gemeenschapssteun!