Comparing ModelMapper and MapStruct in Java: The Power of Automappers

        Learn how to choose between the automappers ModelMapper and MapStruct to increase productivity and maintainability and reduce errors in data mapping.

        In Java applications, data mapping is a common task that involves converting objects from one type to another. This process can become complex and tedious, especially when dealing with large nested classes. To simplify this task, developers often turn to automatic mapping frameworks. Two popular choices for automatic mapping in Java are ModelMapper and MapStruct. In this article, we compare these frameworks and explore why using an automapper is beneficial over manual mapping.

The Need for an Autographer

Before diving into the comparison, let's understand why automappers are preferred over manual mapping. Here are some key reasons:

  1. Productivity : Manual mapping requires writing boilerplate code to transfer data between classes. It can be very time-consuming and error-prone, especially in applications with many classes. Automapper generates the mapping code for you, saving valuable development time.
  2. Maintainability : As the application evolves, classes may change, causing frequent updates to the mapping logic. Automapper handles these changes automatically, reducing the risk of bugs being introduced during updates.
  3. Reduces human error : Manual mapping involves writing repetitive code, which increases the possibility of human error. The automapper ensures consistent and accurate mapping between classes.
  4. Readability : Automapper provides cleaner and more concise mapping code, making it easier for developers to understand the data flow.
  5. Flexibility : Automappers often allow customization and configuration to handle complex mapping scenarios.

ModelMapper 与 MapStruct

ModelMapper and MapStruct are powerful and widely used mapping frameworks in the Java ecosystem. Let's compare them based on various factors:

  1. Ease of use : ModelMapper is known for its simplicity and ease of use. It automatically maps fields with the same name and data type. On the other hand, MapStruct requires the developer to write an explicit mapping interface, which may result in more initial setup, but provides more control over the mapping process.
  2. Performance : Due to its compile-time code generation approach, MapStruct outperforms ModelMapper. ModelMapper relies on reflection, which may have a slight performance overhead.
  3. Configuration : ModelMapper provides a wealth of configuration options to support complex mapping scenarios. MapStruct, being a compile-time mapper, requires an explicit mapping interface, which can be both an advantage (static typing) and a disadvantage (more initial setup).
  4. Customization : Both frameworks allow custom converters to handle specific mapping situations. However, ModelMapper provides more built-in conversions and requires fewer custom converters in many scenarios.

Both ModelMapper and MapStruct are excellent choices for automatic mapping in Java, and the decision to use one or the other depends largely on the specific requirements and preferences of your project.

Beyond DTOs: Various use cases for automappers

Automapper can be used in many ways besides simple DTO mapping. Let's explore some other use cases:

  1. Conversion between layers : Automapper can convert domain objects to DTOs, presentation models, or any other data conversion between application layers.
  2. Adapters and transformations in legacy code : When dealing with legacy codebases, automappers can act as adapters to bridge the gap between old and new class structures. They make it easier to introduce modern data models while still supporting existing code bases.
  3. API versioning : As the application evolves and new API versions are introduced, the automapper can convert the data model between different versions, ensuring backward compatibility and smooth migration.

        This table compares the well-known auto-mapping frameworks in the Java ecosystem: ModelMapper and MapStruct. These frameworks provide efficient solutions for converting objects between different types, eliminating the need for manual mapping and increasing developer productivity.

        ModelMapper stands out for its user-friendly approach requiring minimal setup and configuration. Its simple usage enables developers to quickly start data mapping tasks. The framework's rich configuration options provide great flexibility, enabling it to handle complex mapping scenarios with ease. In addition, ModelMapper supports custom converters, which can easily meet specific mapping requirements.

        On the other hand, MapStruct follows a compile-time code generation approach and thus has superior performance compared to ModelMapper. It requires the definition of an explicit mapping interface, which may require more setup work. However, this approach allows for greater control over the mapping process, providing developers with fine-grained customization.

        ModelMapper and MapStruct integrate seamlessly with popular Java frameworks such as Spring and CDI, allowing developers to incorporate automatic mapping into their projects through dependency injection support. This seamless integration enables developers to take full advantage of the capabilities of these frameworks while benefiting from the powerful mapping capabilities of ModelMapper or MapStruct.

        The choice between ModelMapper and MapStruct depends on project requirements and preferences. ModelMapper is known for its simplicity and feature-rich configuration, while MapStruct offers great performance and more control over the mapping. Developers can confidently choose the most appropriate framework for their specific needs, enhancing the overall development experience and simplifying data mapping tasks in Java applications.

 

Hands-on Session: Mapping Delivery to DeliveryDTO

Let's dive in and we'll use ModelMapper and MapStruct to map classes Deliveryto classes DeliveryDTO.

First let's define Deliveryclasses and DeliveryDTOclasses:

public class Delivery {

    private UUID trackId;

    private LocalDate when;

    private String city;

    private String country;

}



public record DeliveryDTO(String id, String when, String city, String country) {

}

Use a mapping structure:

1. Add the MapStruct dependency to your project. For Maven:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>${org.mapstruct.version}</version>
</dependency>

2. Create a mapping interface:

@Mapper

public interface DeliveryMapper {



    @Mapping(target = "trackId", source = "id")

    Delivery toEntity(DeliveryDTO dto);



    @Mapping(target = "id", source = "trackId")

    DeliveryDTO toDTO(Delivery entity);

}

3. Execute the mapping:

DeliveryMapper mapper = Mappers.getMapper(DeliveryMapper.class);
Delivery delivery = new Delivery(UUID.randomUUID(), LocalDate.now(), "Salvador", "Brazil");
DeliveryDTO dto = this.mapper.toDTO(delivery);
Delivery entity = this.mapper.toEntity(dto);

Use the model mapper:

1. Add the ModelMapper dependency to your project. For Maven:

<dependency>
    <groupId>org.modelmapper</groupId>
    <artifactId>modelmapper</artifactId>
    <version>${org.modelmapper.version}</version>
</dependency>

2. Create a new ModelMapper instance:

ModelMapper modelMapper = new ModelMapper();

3. Set configuration and converters:  Unfortunately, it ModelMapperdoesn't work for records. So we have to first convert it to a class and create and define a converter and UUIDtype LocalDateas shown in the code below.


ModelMapper mapper = new ModelMapper();

mapper.getConfiguration()
        .setFieldMatchingEnabled(true)
        .setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);


Converter<String, UUID> uuidConverter = new AbstractConverter<>() {
    @Override
    protected UUID convert(String source) {
        return UUID.fromString(source);
    }

};


Converter<String, LocalDate> localDateConverter = new AbstractConverter<>() {
    @Override
    protected LocalDate convert(String source) {
       return LocalDate.parse(source);
    }
};


mapper.addConverter(uuidConverter);
mapper.addConverter(localDateConverter);

TypeMap<DeliveryDTO, Delivery> typeMap = this.mapper.createTypeMap(DeliveryDTO.class, Delivery.class);
typeMap.addMappings(mapping -> mapping.using(uuidConverter).map(DeliveryDTO::id, Delivery::setTrackId));

4. Execute the mapping:

Delivery delivery = new Delivery(UUID.randomUUID(), LocalDate.now(), "New York", "USA");
DeliveryDTO deliveryDTO = modelMapper.map(delivery, DeliveryDTO.class);

        In this hands-on lab, we saw how to use ModelMapper and MapStruct to Deliverymap classes to classes DeliveryDTO. Both frameworks make this mapping effortless and allow developers to focus on building the core logic of the application rather than spending time doing manual mapping.

in conclusion

        Automappers such as ModelMapper and MapStruct offer significant advantages over manual mapping, increasing productivity, maintainability, and reducing errors in data mapping. Choosing the right mapper depends on the specific needs of your project. Still, ModelMapper and MapStruct are powerful tools that simplify complex mapping scenarios and help developers deliver more efficient and maintainable Java applications.

Guess you like

Origin blog.csdn.net/qq_28245905/article/details/132224352