SoFunction
Updated on 2025-04-05

How to use MapStruct to perform Java Bean mapping

Guide to Java Bean Mapping with MapStruct

Introduction

MapStruct is an annotation processor for Java Bean mapping. It generates type-safe and excellent performance mapping code through annotations, avoiding manual writing of duplicate boilerplate code, and is suitable for converting one Java Bean type to another.

The main features of MapStruct

  1. Type safety: Generate mapping code at compile time to avoid runtime errors.
  2. high performance: The generated code is pure Java code, without reflection mechanism, and has very high performance.
  3. concise: A large amount of boilerplate code is reduced, developers only need to define interfaces, and MapStruct is automatically generated and implemented.
  4. Customizable: Supports custom mapping, default values, conversion methods, etc.

Depend on configuration

Using MapStruct requires adding corresponding dependencies. Take Maven as an example:

<dependencies>
    <dependency>
        <groupId></groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.</version>
    </dependency>
    <dependency>
        <groupId></groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.5.</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

If using Gradle:

dependencies {
    implementation ':mapstruct:1.5.'
    annotationProcessor ':mapstruct-processor:1.5.'
}

Steps to use MapStruct

Define the mapping interface

Create an interface and use@MapperAnnotation marks it.

import ;
import ;
import ;
import ;

/**
  * The CarMapper interface defines the mapping relationship between Car and CarDto.
  * Use @Mapper annotation to mark the interface and set typeConversionPolicy to ,
  * To ensure that the compile error occurs when the type conversion is incorrect.
  */
@Mapper(typeConversionPolicy = )
public interface CarMapper {
    CarMapper INSTANCE = ();

    /**
      * Map the Car entity to CarDto.
      * @param car Source Car object
      * @return Map CarDto object
      */
    @Mapping(source = "numberOfSeats", target = "seatCount")
    @Mapping(source = "", target = "engineType")
    CarDto carToCarDto(Car car);
}

Define source and target classes

/**
  * Car entity class
  */
public class Car {
    private String make; // Manufacturer    private int numberOfSeats; // Number of seats    private Engine engine; // Engine
    // getters and setters}

/**
  * CarDto data transfer object
  */
public class CarDto {
    private String make; // Manufacturer    private int seatCount; // Number of seats    private String engineType; // Engine type
    // getters and setters}

/**
  * Engine Entity Class
  */
public class Engine {
    private String type; // Engine type
    // getters and setters}

Generate mapping code

Use a build tool such as Maven or Gradle to execute the build process, and MapStruct will generate the corresponding mapped implementation class based on the interface definition.

/**
  * CarMapper implementation class, automatically generated by MapStruct.
  */
public class CarMapperImpl implements CarMapper {
    @Override
    public CarDto carToCarDto(Car car) {
        if (car == null) {
            return null;
        }
        CarDto carDto = new CarDto();
        (());
        (());
        if (() != null) {
            (().getType());
        }
        return carDto;
    }
}

Calling the mapping method

/**
  * Demonstrate how to map Car entities to CarDto using CarMapper.
  */
public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        ("Toyota");
        (5);
        Engine engine = new Engine();
        ("V8");
        (engine);

        CarDto carDto = (car);
        (carDto);
    }
}

Deep and shallow copies

  • Light copy: Copy the references to the basic data type attributes and reference type attributes of the object. The reference type attribute itself is not copied.
  • Deep copy: Copy all properties of an object, including the object itself referenced by the reference type attribute.

MapStruct is used for light copying by default, that is, the reference type attribute will refer to the same instance of the source object in the target object. If you need to make a deep copy, you can manually write a custom mapping method.

Collection copy

MapStruct can automatically handle mappings of collection types. For example:

import ;
import ;
import ;
import ;

import ;

/**
  * The CarMapper interface defines the mapping relationship between Car and CarDto.
  * Use @Mapper annotation to mark the interface and set typeConversionPolicy to ,
  * To ensure that the compile error occurs when the type conversion is incorrect.
  */
@Mapper(typeConversionPolicy = )
public interface CarMapper {
    CarMapper INSTANCE = ();

    /**
      * Map the Car entity to CarDto.
      * @param car Source Car object
      * @return Map CarDto object
      */
    @Mapping(source = "numberOfSeats", target = "seatCount")
    @Mapping(source = "", target = "engineType")
    CarDto carToCarDto(Car car);

    /**
      * Map the Car entity list to a CarDto list.
      * @param cars Source Car object list
      * @return Mapdated CarDto object list
      */
    List&lt;CarDto&gt; carsToCarDtos(List&lt;Car&gt; cars);
}

Compile-time error handling

MapStruct performs type checking at compile time, and if the mapping is incorrect, a compilation error will be thrown. Available@MapperAnnotatedtypeConversionPolicyProperties to configure behavior when an error occurs during type conversion, e.g.

import ;
import ;
import ;
import ;

/**
  * The CarMapper interface defines the mapping relationship between Car and CarDto.
  * Use @Mapper annotation to mark the interface and set typeConversionPolicy to ,
  * To ensure that the compile error occurs when the type conversion is incorrect.
  */
@Mapper(typeConversionPolicy = )
public interface CarMapper {
    CarMapper INSTANCE = ();

    /**
      * Map the Car entity to CarDto.
      * @param car Source Car object
      * @return Map CarDto object
      */
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
}

In the above example, if the type conversion is incorrect or cannot be converted, an error will be reported at compile time, ensuring that all type conversions are handled correctly.

Complete examples and document generation

Here is a complete example, including source code and generated mapping code, and how to generate documentation.

source code

Source and target classes:

/**
  * Car entity class
  */
public class Car {
    private String make; // Manufacturer    private int numberOfSeats; // Number of seats    private Engine engine; // Engine
    // getters and setters}

/**
  * CarDto data transfer object
  */
public class CarDto {
    private String make; // Manufacturer    private int seatCount; // Number of seats    private String engineType; // Engine type
    // getters and setters}

/**
  * Engine Entity Class
  */
public class Engine {
    private String type; // Engine type
    // getters and setters}

Mapping interface:

import ;
import ;
import ;
import ;

import ;

/**
  * The CarMapper interface defines the mapping relationship between Car and CarDto.
  * Use @Mapper annotation to mark the interface and set typeConversionPolicy to ,
  * To ensure that the compile error occurs when the type conversion is incorrect.
  */
@Mapper(typeConversionPolicy = )
public interface CarMapper {
    CarMapper INSTANCE = ();

    /**
      * Make Car Real

 The body maps to CarDto.
      * @param car Source Car object
      * @return Map CarDto object
      */
    @Mapping(source = "numberOfSeats", target = "seatCount")
    @Mapping(source = "", target = "engineType")
    CarDto carToCarDto(Car car);

    /**
      * Map the Car entity list to a CarDto list.
      * @param cars Source Car object list
      * @return Mapdated CarDto object list
      */
    List&lt;CarDto&gt; carsToCarDtos(List&lt;Car&gt; cars);
}

Generated mapping code

MapStruct will automatically generate the following implementation class:

/**
  * CarMapper implementation class, automatically generated by MapStruct.
  */
public class CarMapperImpl implements CarMapper {
    @Override
    public CarDto carToCarDto(Car car) {
        if (car == null) {
            return null;
        }
        CarDto carDto = new CarDto();
        (());
        (());
        if (() != null) {
            (().getType());
        }
        return carDto;
    }

    @Override
    public List&lt;CarDto&gt; carsToCarDtos(List&lt;Car&gt; cars) {
        if (cars == null) {
            return null;
        }
        List&lt;CarDto&gt; list = new ArrayList&lt;&gt;(());
        for (Car car : cars) {
            (carToCarDto(car));
        }
        return list;
    }
}

Generate a document

You can use the Javadoc tool to generate documents, as shown below:

javadoc -d doc -sourcepath src/main/java -subpackages 

The generated document will contain detailed descriptions of all classes and interfaces, including fields, methods, and comments.

Summarize

This guide allows you to understand the basic features of MapStruct, how to configure dependencies, usage steps, the differences between deep and shallow copies, mapping of collection types, and how to handle compile-time errors.

MapStruct can greatly improve the maintainability and performance of code and is a powerful tool for Java Bean mapping.

The above is personal experience. I hope you can give you a reference and I hope you can support me more.