# MapStruct Mapper

## About

MapStruct is a code generator that simplifies the implementation of mappings between Java bean types based on a convention-over-configuration approach. It is a tool designed to help developers map data from one Java object to another. It is a popular choice for mapping objects, especially in large-scale enterprise applications, due to its performance and ease of use.

Refer to documentation for more details: <https://mapstruct.org/documentation/1.5/reference/html/>

{% hint style="info" %}
**What is "Convention-Over-Configuration"?**

"Convention-over-configuration" is a software design principle used to reduce the number of decisions developers need to make, without sacrificing flexibility. In simpler terms, it means that the framework will assume reasonable default behavior unless the developer specifies otherwise. This approach minimizes the need for extensive configuration by relying on common conventions.

**How Does MapStruct Use Convention-Over-Configuration?**

MapStruct uses this principle to simplify object mappings by following these conventions

* **Property Name Matching**:
  * By default, MapStruct maps properties in source and target objects that have the same name and compatible types.
  * For example, if we have a `UserDTO` class with a `name` field and a `UserEntity` class with a `name` field, MapStruct will automatically map `UserDTO.name` to `UserEntity.name`.
* **Type Matching**:
  * MapStruct can automatically convert between types that have a clear conversion path (e.g., `String` to `int`, `Date` to `String`).
  * This reduces the need for explicit type conversion configuration.
* **Default Method Generation**:
  * MapStruct generates implementation code for the mapping methods based on the interface definitions provided by the developer.
  * For instance, if we define a method `UserDTO toUserDTO(UserEntity entity);` in a mapper interface, MapStruct will generate the implementation for this method, mapping each field based on conventions.
    {% endhint %}

## Maven POM Dependency and Plugin

Include the required dependencies in pom.xml file.

```xml
<!-- This dependency includes the core MapStruct library which provides 
the API and main functionality for object mapping. -->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<!-- This dependency includes the MapStruct annotation processor which 
generates the implementation of the mapper interfaces at compile time. -->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.5.Final</version>
</dependency>
```

It comprises the following artifacts:

* *org.mapstruct:mapstruct*: contains the required annotations such as `@Mapping`
* *org.mapstruct:mapstruct-processor*: contains the annotation processor which generates mapper implementations

```xml
<!-- The maven-compiler-plugin is a Maven plugin used to compile Java source files. 
In the context of using MapStruct, it is configured to ensure that the MapStruct annotation 
processor is correctly set up during the compilation phase. -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${maven-compiler-plugin.version}</version>
    <configuration>
        <annotationProcessorPaths>
            <path>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>${mapstruct.version}</version>
            </path>
        </annotationProcessorPaths>
        <useIncrementalCompilation>false</useIncrementalCompilation>
        <showWarnings>true</showWarnings>
        <compilerArgs>
            <arg>-Amapstruct.suppressGeneratorTimestamp=true</arg>
            <arg>-Amapstruct.suppressGeneratorVersionInfoComment=true</arg>
            <arg>-Amapstruct.verbose=true</arg>
        </compilerArgs>
    </configuration>
</plugin>
```

MapStruct processor options -

<table data-full-width="true"><thead><tr><th width="207">Option</th><th width="605">Purpose</th><th>Default</th></tr></thead><tbody><tr><td><code>mapstruct. suppressGeneratorTimestamp</code></td><td>If set to <code>true</code>, the creation of a time stamp in the <code>@Generated</code> annotation in the generated mapper classes is suppressed.</td><td><code>false</code></td></tr><tr><td><code>mapstruct.verbose</code></td><td>If set to <code>true</code>, MapStruct in which MapStruct logs its major decisions. Note, at the moment of writing in Maven, also <code>showWarnings</code> needs to be added due to a problem in the maven-compiler-plugin configuration.</td><td><code>false</code></td></tr><tr><td><code>mapstruct. suppressGeneratorVersionInfoComment</code></td><td>If set to <code>true</code>, the creation of the <code>comment</code>attribute in the <code>@Generated</code> annotation in the generated mapper classes is suppressed. The comment contains information about the version of MapStruct and about the compiler used for the annotation processing.</td><td><code>false</code></td></tr><tr><td><code>mapstruct.defaultComponentModel</code></td><td><p>The name of the component model based on which mappers should be generated.</p><p>Supported values are:</p><ul><li><code>default</code>: the mapper uses no component model, instances are typically retrieved via <code>Mappers#getMapper(Class)</code></li><li><code>cdi</code>: the generated mapper is an application-scoped (from javax.enterprise.context or jakarta.enterprise.context, depending on which one is available with javax.inject having priority) CDI bean and can be retrieved via <code>@Inject</code></li><li><code>spring</code>: the generated mapper is a singleton-scoped Spring bean and can be retrieved via <code>@Autowired</code> or lombok annotation like <code>@RequiredArgsConstructor</code></li><li><code>jsr330</code>: the generated mapper is annotated with {@code @Named} and can be retrieved via <code>@Inject</code> (from javax.inject or jakarta.inject, depending which one is available with javax.inject having priority), e.g. using Spring</li><li><code>jakarta</code>: the generated mapper is annotated with {@code @Named} and can be retrieved via <code>@Inject</code> (from jakarta.inject), e.g. using Spring</li><li><code>jakarta-cdi</code>: the generated mapper is an application-scoped (from jakarta.enterprise.context) CDI bean and can be retrieved via <code>@Inject</code></li></ul><p>If a component model is given for a specific mapper via <code>@Mapper#componentModel()</code>, the value from the annotation takes precedence.</p></td><td><code>default</code></td></tr><tr><td><code>mapstruct.defaultInjectionStrategy</code></td><td><p>The type of the injection in mapper via parameter <code>uses</code>. This is only used on annotated based component models such as CDI, Spring and JSR 330.</p><p>Supported values are:</p><ul><li><code>field</code>: dependencies will be injected in fields</li><li><code>constructor</code>: will be generated constructor. Dependencies will be injected via constructor.</li></ul><p>When CDI <code>componentModel</code> a default constructor will also be generated. If a injection strategy is given for a specific mapper via <code>@Mapper#injectionStrategy()</code>, the value from the annotation takes precedence over the option.</p></td><td><code>field</code></td></tr><tr><td><code>mapstruct.unmappedTargetPolicy</code></td><td><p>The default reporting policy to be applied in case an attribute of the target object of a mapping method is not populated with a source value.</p><p>Supported values are:</p><ul><li><code>ERROR</code>: any unmapped target property will cause the mapping code generation to fail</li><li><code>WARN</code>: any unmapped target property will cause a warning at build time</li><li><code>IGNORE</code>: unmapped target properties are ignored</li></ul><p>If a policy is given for a specific mapper via <code>@Mapper#unmappedTargetPolicy()</code>, the value from the annotation takes precedence. If a policy is given for a specific bean mapping via <code>@BeanMapping#unmappedTargetPolicy()</code>, it takes precedence over both <code>@Mapper#unmappedTargetPolicy()</code> and the option.</p></td><td><code>WARN</code></td></tr><tr><td><code>mapstruct.unmappedSourcePolicy</code></td><td><p>The default reporting policy to be applied in case an attribute of the source object of a mapping method is not populated with a target value.</p><p>Supported values are:</p><ul><li><code>ERROR</code>: any unmapped source property will cause the mapping code generation to fail</li><li><code>WARN</code>: any unmapped source property will cause a warning at build time</li><li><code>IGNORE</code>: unmapped source properties are ignored</li></ul><p>If a policy is given for a specific mapper via <code>@Mapper#unmappedSourcePolicy()</code>, the value from the annotation takes precedence. If a policy is given for a specific bean mapping via <code>@BeanMapping#ignoreUnmappedSourceProperties()</code>, it takes precedence over both <code>@Mapper#unmappedSourcePolicy()</code> and the option.</p></td><td><code>WARN</code></td></tr><tr><td><code>mapstruct. disableBuilders</code></td><td>If set to <code>true</code>, then MapStruct will not use builder patterns when doing the mapping. This is equivalent to doing <code>@Mapper( builder = @Builder( disableBuilder = true ) )</code> for all of our mappers.</td><td><code>false</code></td></tr></tbody></table>

## **Core Features**

MapStruct provides a set of core features that allow to map properties between different objects seamlessly. These include:

* **Basic Type Mapping**: MapStruct automatically maps properties with the same name and compatible types.
* **Handling Null Values**: By default, MapStruct maps null values, but we can customize this behavior.
* **Customizing Mappings with `@Mapping`**: This annotation allows to define how individual fields are mapped.

## Data type conversions <a href="#datatype-conversions" id="datatype-conversions"></a>

It is possible to have mapped attribute with the same type or different in the source and target objects. We need to understand how MapStruct deals with such data type conversions.

### Implicit type conversions <a href="#implicit-type-conversions" id="implicit-type-conversions"></a>

Mapstruct applies the following conversion automatically.

* Between all Java primitive data types and their corresponding wrapper types, e.g. between `int` and `Integer`, `boolean` and `Boolean` etc. When converting a wrapper type into the corresponding primitive type a `null` check will be performed.
* Between all Java primitive number types and the wrapper types, e.g. between `int` and `long` or `byte` and `Integer`

{% hint style="info" %}
The `Mapper` and `MapperConfig` annotations have a method `typeConversionPolicy` to control warnings / errors. Due to backward compatibility reasons the default value is `ReportingPolicy.IGNORE`.
{% endhint %}

* Between all Java primitive types (including their wrappers) and `String`, e.g. between `int` and `String` or `Boolean`and `String`. A format string as understood by `java.text.DecimalFormat` can be specified.

```java
@Mapper
public interface CarMapper {

    @Mapping(source = "price", numberFormat = "$#.00")
    CarDto carToCarDto(Car car);

    @IterableMapping(numberFormat = "$#.00")
    List<String> prices(List<Integer> prices);
}
```

* Between `enum` types and `String`.
* Between big number types (`java.math.BigInteger`, `java.math.BigDecimal`) and Java primitive types (including their wrappers) as well as String. A format string `java.text.DecimalFormat` can be specified.

```
@Mapper
public interface EventMapper {

    @Mapping(source = "fee", numberFormat = "#.##E0")
    EventDto eventToEventDto(Event event);

}
```

* Between `JAXBElement<T>` and `T`, `List<JAXBElement<T>>` and `List<T>`
* Between `java.util.Calendar`/`java.util.Date` and JAXB’s `XMLGregorianCalendar`
* Between `java.util.Date`/`XMLGregorianCalendar` and `String`. A format string as understood by `java.text.SimpleDateFormat` can be specified via the `dateFormat` option

```
@Mapper
public interface EventMapper {

    @Mapping(source = "paymenDate", dateFormat = "dd.MM.yyyy")
    EventDto eventToEventDto(Event event);

    @IterableMapping(dateFormat = "dd.MM.yyyy")
    List<String> stringListToDateList(List<Date> dates);
}
```

* Between Jodas `org.joda.time.DateTime`, `org.joda.time.LocalDateTime`, `org.joda.time.LocalDate`, `org.joda.time.LocalTime` and `String`. A format string as understood by `java.text.SimpleDateFormat` can be specified via the `dateFormat` option (see above).
* Between Jodas `org.joda.time.DateTime` and `javax.xml.datatype.XMLGregorianCalendar`, `java.util.Calendar`.
* Between Jodas `org.joda.time.LocalDateTime`, `org.joda.time.LocalDate` and `javax.xml.datatype.XMLGregorianCalendar`, `java.util.Date`.
* Between `java.time.LocalDate`, `java.time.LocalDateTime` and `javax.xml.datatype.XMLGregorianCalendar`.
* Between `java.time.ZonedDateTime`, `java.time.LocalDateTime`, `java.time.LocalDate`, `java.time.LocalTime`from Java 8 Date-Time package and `String`. A format string as understood by `java.text.SimpleDateFormat` can be specified via the `dateFormat` option (see above).
* Between `java.time.Instant`, `java.time.Duration`, `java.time.Period` from Java 8 Date-Time package and `String` using the `parse` method in each class to map from `String` and using `toString` to map into `String`.
* Between `java.time.ZonedDateTime` from Java 8 Date-Time package and `java.util.Date` where, when mapping a `ZonedDateTime` from a given `Date`, the system default timezone is used.
* Between `java.time.LocalDateTime` from Java 8 Date-Time package and `java.util.Date` where timezone UTC is used as the timezone.
* Between `java.time.LocalDate` from Java 8 Date-Time package and `java.util.Date` / `java.sql.Date` where timezone UTC is used as the timezone.
* Between `java.time.Instant` from Java 8 Date-Time package and `java.util.Date`.
* Between `java.time.ZonedDateTime` from Java 8 Date-Time package and `java.util.Calendar`.
* Between `java.sql.Date` and `java.util.Date`
* Between `java.sql.Time` and `java.util.Date`
* Between `java.sql.Timestamp` and `java.util.Date`
* When converting from a `String`, omitting `Mapping#dateFormat`, it leads to usage of the default pattern and date format symbols for the default locale. An exception to this rule is `XmlGregorianCalendar` which results in parsing the `String` according to XML Schema.
* Between `java.util.Currency` and `String`.
  * When converting from a `String`, the value needs to be a valid ISO-4217 alphabetic code otherwise an `IllegalArgumentException` is thrown.
* Between `java.util.UUID` and `String`.
  * When converting from a `String`, the value needs to be a valid UUID otherwise an `IllegalArgumentException` is thrown.
* Between `String` and `StringBuilder`
* Between `java.net.URL` and `String`.
  * When converting from a `String`, the value needs to be a valid URL otherwise a `MalformedURLException` is thrown.

### Mapping nested object references <a href="#mapping-object-references" id="mapping-object-references"></a>

Suppose, Event has reference to Address object.

```java
@Mapper
public interface EventMapper {
    EventDto eventToEventDto(Event event);

    AddressDto addressToAddressDto(Address address);
}
```

### Controlling nested bean mappings <a href="#controlling-nested-bean-mappings" id="controlling-nested-bean-mappings"></a>

MapStruct will generate a method based on the name of the source and target property. In many occasions these names do not match. The ‘.’ notation in an `@Mapping` source or target type can be used to control how properties should be mapped when names do not match.

```java
@Mapper
public interface FishTankMapper {
    @Mapping(target = "fish.kind", source = "fish.type")
    @Mapping(target = "fish.name", ignore = true)
    @Mapping(target = "ornament", source = "interior.ornament")
    @Mapping(target = "material.materialType", source = "material")
    @Mapping(target = "quality.report.organisation.name", source = "quality.report.organisationName")
    FishTankDto map( FishTank source );
}
```

### Invoking custom mapping method <a href="#invoking-custom-mapping-method" id="invoking-custom-mapping-method"></a>

Sometimes, some fields require custom logic. For example, MapStruct will take the entire parameter `source` and generate code to call the custom method `mapVolume`in order to map the `FishTank` object to the target property `volume`.

```java
public class FishTank {
    Fish fish;
    String material;
    Quality quality;
    int length;
    int width;
    int height;
}

public class FishTankWithVolumeDto {
    FishDto fish;
    MaterialDto material;
    QualityDto quality;
    VolumeDto volume;
}

public class VolumeDto {
    int volume;
    String description;
}

@Mapper
public abstract class FishTankMapperWithVolume {

    @Mapping(target = "fish.kind", source = "source.fish.type")
    @Mapping(target = "material.materialType", source = "source.material")
    @Mapping(target = "quality.document", source = "source.quality.report")
    @Mapping(target = "volume", source = "source")
    abstract FishTankWithVolumeDto map(FishTank source);

    VolumeDto mapVolume(FishTank source) {
        int volume = source.length * source.width * source.height;
        String desc = volume < 100 ? "Small" : "Large";
        return new VolumeDto(volume, desc);
    }
}
```

### Invoking other mappers <a href="#invoking-other-mappers" id="invoking-other-mappers"></a>

MapStruct can also invoke mapping methods defined in other classes, be it mappers generated by MapStruct or hand-written mapping methods. For eg, when generating code for the implementation of the `carToCarDto()` method, MapStruct will look for a method which maps a `Date` object into a String, find it on the `DateMapper` class and generate an invocation of `asString()` for mapping the `manufacturingDate` attribute.

```java
// Manually implemented class
public class DateMapper {
    public String asString(Date date) {
        return date != null ? new SimpleDateFormat( "yyyy-MM-dd" )
            .format( date ) : null;
    }

    public Date asDate(String date) {
        try {
            return date != null ? new SimpleDateFormat( "yyyy-MM-dd" )
                .parse( date ) : null;
        }
        catch ( ParseException e ) {
            throw new RuntimeException( e );
        }
    }
}

// Using the DateMapper in a mapper
@Mapper(uses=DateMapper.class)
public interface CarMapper {
    CarDto carToCarDto(Car car);
}
```

### Passing context or state objects to custom methods <a href="#passing-context" id="passing-context"></a>

Additional *context* or *state* information can be passed through generated mapping methods to custom methods with `@Context` parameters. Such parameters are passed to other mapping methods, `@ObjectFactory` methods or `@BeforeMapping` / `@AfterMapping` methods when applicable and can thus be used in custom code.

```java
public abstract CarDto toCar(Car car, @Context Locale translationLocale);

protected OwnerManualDto translateOwnerManual(OwnerManual ownerManual, @Context Locale locale) {
    // manually implemented logic to translate the OwnerManual with the given Locale
}
```

```java
//GENERATED CODE
public CarDto toCar(Car car, Locale translationLocale) {
    if ( car == null ) {
        return null;
    }

    CarDto carDto = new CarDto();

    carDto.setOwnerManual( translateOwnerManual( car.getOwnerManual(), translationLocale );
    // more generated mapping code

    return carDto;
}
```

### Mapping method resolution <a href="#mapping-method-resolution" id="mapping-method-resolution"></a>

When mapping a property from one type to another, MapStruct looks for the most specific method which maps the source type into the target type. The method may either be declared on the same mapper interface or on another mapper which is registered via `@Mapper#uses()`

### Combining qualifiers @Named with defaults <a href="#combining_qualifiers_with_defaults" id="combining_qualifiers_with_defaults"></a>

Default value will be used if the returned value from the @Named method is null.

```java
@Mapper
public interface MovieMapper {
     @Mapping( target = "category", qualifiedByName = "CategoryToString", defaultValue = "DEFAULT" )
     GermanRelease toGerman( OriginalRelease movies );

     @Named("CategoryToString")
     default String defaultValueForQualifier(Category cat) {
         // some mapping logic
     }
}
```

## Basic Mapping

The `@Mapper` annotation causes the MapStruct code generator to create an implementation of the `UserMapper` interface during build-time. MapStruct will generate a method based on the name of the source and target property.

{% hint style="info" %}

* When a property has the same name as its target entity counterpart, it will be mapped implicitly.
* When a property has a different name in the target entity, its name can be specified via the `@Mapping` annotation.
* The DTO or the objects being mapped should have getter setter to access fields.
* `@BeanMapping` with the `ignoreByDefault` attribute in MapStruct allows us to specify that all properties should be ignored by default, and we can then explicitly specify which properties to include in the mapping. This can be useful for partial updates or when you want to map only a subset of the properties.
* In some cases, it can be required to manually implement a specific mapping from one type to another which can’t be generated by MapStruct. Use the Default method for such case.
* In some cases, we may need mappings which don’t create a new instance of the target type but instead update an existing instance of that type. We can achieve this by adding a parameter for the target object and marking this parameter with `@MappingTarget.` There may be only one parameter marked as mapping target.
* MapStruct also supports mappings of `public` fields that have no getters/setters. MapStruct will use the fields as read/write accessor if it cannot find suitable getter/setter methods for the property. A field is considered as a read accessor if it is `public` or `public final`. If a field is `static` it is not considered as a read accessor. A field is considered as a write accessor only if it is `public`. If a field is `final` and/or `static` it is not considered as a write accessor.
  {% endhint %}

```java
package mapper;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper(componentModel = "spring")
public interface UserMapper {

    // UserId will be mapped implicitly since field name from both the object is same
    @Mapping(target = "userName", source = "name")
    @Mapping(target = "userEmail", source = "email")
    @Mapping(target = "addressDTO.pincode", source = "pincode")
    UserDTO mapToUserDTO(User user);
    
    // All properties need to map explicitly
    @BeanMapping(ignoreByDefault = true)
    AddressDTO mapToAddressDTO(Address address);
    
    // Implement custom method if it has complex mapping logic which cannot be handled by mapstruct
    default PersonDto personToPersonDto(Person person) {
        //hand-written mapping logic
    }
    
    // Mapping methods with several source parameters
    @Mapping(target = "description", source = "person.description")
    @Mapping(target = "houseNumber", source = "address.houseNo")
    DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
    
    // Mapping nested bean properties to current target. "." as target
    // Generated code will map every property from CustomerDto.record and Customer.account
    // to Customer directly, without manually naming. 
    @Mapping( target = "name", source = "record.name" )
    @Mapping( target = ".", source = "record" )
    @Mapping( target = ".", source = "account" )
    Customer customerDtoToCustomer(CustomerDto customerDto);
    
    // Updating existing bean instances
    // In some cases, we need to update an existing instance of a type rather a new instance
    void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
    
    // We can return the target type as well
    Car updateAndReturnCarFromDto(CarDto carDto, @MappingTarget Car car);
    
    // Here, say CustomerDto has only public fields but no getter setter. Whereas Customer has private fields with getter setter
    // Mapstruct allows mapping even if no getter setter provided it satisfies accessor conditons
    @Mapping(target = "name", source = "customerName")
    Customer toCustomer(CustomerDto customerDto);
    
    // Annotation @InheritInverseConfiguration indicates that a method shall inherit the inverse configuration of the corresponding reverse method.
    @InheritInverseConfiguration
    CustomerDto fromCustomer(Customer customer);
}
```

### Default values and constants <a href="#default-values-and-constants" id="default-values-and-constants"></a>

Default values and constants are specified as String values. If the source is null, default value will be used.

```java
@Mapper(uses = StringListMapper.class)
public interface SourceTargetMapper {
    SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );

    @Mapping(target = "stringProperty", source = "stringProp", defaultValue = "undefined")
    @Mapping(target = "longProperty", source = "longProp", defaultValue = "-1")
    @Mapping(target = "stringConstant", constant = "Constant Value")
    @Mapping(target = "integerConstant", constant = "14")
    @Mapping(target = "longWrapperConstant", constant = "3001")
    @Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014")
    @Mapping(target = "stringListConstants", constant = "jack-jill-tom")
    Target sourceToTarget(Source s);
}
```

### Expressions <a href="#expressions" id="expressions"></a>

As per documentation, MapStruct will not validate the java expression at generation-time, but errors will show up in the generated classes during compilation. Fully qualified package name is specified because MapStruct does not take care of the import of the `TimeAndFormat` class (unless it’s used otherwise explicitly in the `SourceTargetMapper`). This can be resolved by defining `imports` on the `@Mapper` annotation.

```java
@Mapper
public interface SourceTargetMapper {

    SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );

    @Mapping(target = "timeAndFormat",
         expression = "java( new org.sample.TimeAndFormat( s.getTime(), s.getFormat() ) )")
    Target sourceToTarget(Source s);
}


imports org.sample.TimeAndFormat;

@Mapper( imports = TimeAndFormat.class )
public interface SourceTargetMapper {

    SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );

    @Mapping(target = "timeAndFormat",
         expression = "java( new TimeAndFormat( s.getTime(), s.getFormat() ) )")
    Target sourceToTarget(Source s);
}
```

### Default Expressions <a href="#default-expressions" id="default-expressions"></a>

Default expressions are a combination of default values and expressions. They will only be used when the source attribute is `null`.

```java
imports java.util.UUID;

@Mapper( imports = UUID.class )
public interface SourceTargetMapper {

    SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );

    @Mapping(target="id", source="sourceId", defaultExpression = "java( UUID.randomUUID().toString() )")
    Target sourceToTarget(Source s);
}
```

### Subclass Mapping <a href="#sub-class-mappings" id="sub-class-mappings"></a>

It is used when both input and result types have an inheritance relation. Suppose an `Apple` and a `Banana`, which are both specializations of `Fruit`.

```java
@Mapper
public interface FruitMapper {
    @SubclassMapping( source = AppleDto.class, target = Apple.class )
    @SubclassMapping( source = BananaDto.class, target = Banana.class )
    Fruit map( FruitDto source );
}
```

If we would just use a normal mapping both the `AppleDto` and the `BananaDto` would be made into a `Fruit` object, instead of an `Apple` and a `Banana` object.

### Determining the result type <a href="#determining-result-type" id="determining-result-type"></a>

When result types have an inheritance relation, selecting either mapping method (`@Mapping`) or a factory method (`@BeanMapping`) can become ambiguous. Suppose an Apple and a Banana, which are both specializations of Fruit.

```java
public class FruitFactory {
    public Apple createApple() {
        return new Apple( "Apple" );
    }

    public Banana createBanana() {
        return new Banana( "Banana" );
    }
}

@Mapper( uses = FruitFactory.class )
public interface FruitMapper {
    @BeanMapping( resultType = Apple.class )
    Fruit map( FruitDto source );
}
```

### Controlling mapping result for 'null' arguments <a href="#mapping-result-for-null-arguments" id="mapping-result-for-null-arguments"></a>

As per documentation, when the source argument of the mapping method equals `null` then by default `null` will be returned.

However, by specifying `nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT` on `@BeanMapping`, `@IterableMapping`, `@MapMapping`, or globally on `@Mapper` or `@MapperConfig`, the mapping result can be altered to return empty **default** values. This means for:

* **Bean mappings**: an 'empty' target bean will be returned, with the exception of constants and expressions, they will be populated when present.
* **Iterables / Arrays**: an empty iterable will be returned.
* **Maps**: an empty map will be returned.

### Source presence checking and Conditional Mapping

Some frameworks generate bean properties that have a source presence checker. Often this is in the form of a method `hasXYZ`, `XYZ` being a property on the source bean in a bean mapping method. MapStruct will call this `hasXYZ` instead of performing a `null` check when it finds such `hasXYZ` method.

Conditional Mapping is a type of [Source presence checking](https://mapstruct.org/documentation/1.5/reference/html/#source-presence-check). The difference is that it allows users to write custom condition methods that will be invoked to check if a property needs to be mapped or not.

A custom condition method is a method that is annotated with `org.mapstruct.Condition` and returns `boolean`.

e.g. if you only want to map a String property when it is not \`null, and it is not empty then you can do something like:

```java
@Mapper
public interface CarMapper {
    CarDto carToCarDto(Car car);

    @Condition
    default boolean isNotEmpty(String value) {
        return value != null && !value.isEmpty();
    }
}
```

When using this in combination with an update mapping method it will replace the `null-check` there, for example:

```java
@Mapper
public interface CarMapper {
    CarDto carToCarDto(Car car, @MappingTarget CarDto carDto);

    @Condition
    default boolean isNotEmpty(String value) {
        return value != null && !value.isEmpty();
    }
}
```

### Exceptions <a href="#exceptions" id="exceptions"></a>

Calling applications may require handling of exceptions when calling a mapping method. These exceptions could be thrown by hand-written logic and by the generated built-in mapping methods or type-conversions of MapStruct.

```java
@Mapper(uses = HandWritten.class)
public interface CarMapper {
    CarDto carToCarDto(Car car) throws GearException;
}

public class HandWritten {
    private static final String[] GEAR = {"ONE", "TWO", "THREE", "OVERDRIVE", "REVERSE"};

    public String toGear(Integer gear) throws GearException, FatalException {
        if ( gear == null ) {
            throw new FatalException("null is not a valid gear");
        }

        if ( gear < 0 && gear > GEAR.length ) {
            throw new GearException("invalid gear");
        }
        return GEAR[gear];
    }
}
```

### Using builders <a href="#mapping-with-builders" id="mapping-with-builders"></a>

MapStruct also supports mapping of immutable types via builders. When performing a mapping MapStruct checks if there is a builder for the type being mapped. This is done via the `BuilderProvider` SPI. If a Builder exists for a certain type, then that builder will be used for the mappings.

```java
// Builder Pattern for Person class
public class Person {
    private final String name;

    protected Person(Person.Builder builder) {
        this.name = builder.name;
    }
    public static Person.Builder builder() {
        return new Person.Builder();
    }

    public static class Builder {

        private String name;

        public Builder name(String name) {
            this.name = name;
            return this;
        }
        public Person create() {
            return new Person( this );
        }
    }
}

// Mapstruct mapper
@Mapper(componentModel = "spring")
public interface PersonMapper {
    Person map(PersonDto dto);
}
```

### Using Constructors <a href="#mapping-with-constructors" id="mapping-with-constructors"></a>

MapStruct supports using constructors for mapping target types. When doing a mapping MapStruct checks if there is a builder for the type being mapped. If there is no builder, then MapStruct looks for a single accessible constructor.

* If a constructor is annotated with an annotation *named* `@Default` it will be used.
* If a single public constructor exists then it will be used to construct the object, and the other non public constructors will be ignored.
* If a parameterless constructor exists then it will be used to construct the object, and the other constructors will be ignored.
* If there are multiple eligible constructors then there will be a compilation error due to ambiguous constructors.

```java
public class Vehicle {
    protected Vehicle() { }
    // MapStruct will use this constructor, because it is a single public constructor
    public Vehicle(String color) { }
}

public class Car {
    // MapStruct will use this constructor, because it is a parameterless empty constructor
    public Car() { }
    public Car(String make, String color) { }
}

public class Truck {
    public Truck() { }
    // MapStruct will use this constructor, because it is annotated with @Default
    @Default
    public Truck(String make, String color) { }
}

public class Van {
    // There will be a compilation error when using this class because MapStruct cannot pick a constructor
    public Van(String make) { }
    public Van(String make, String color) { }
}

// Mapper
@Mapper(componentModel = "spring")
public interface PersonMapper {
    Person map(PersonDto dto);
}
```

### Mapping `Map` to Bean <a href="#mapping-map-to-bean" id="mapping-map-to-bean"></a>

We want to map `Map<String, ???>` into a specific bean. When a raw map or a map that does not have a String as a key is used, then a warning will be generated.

```java
public class Customer {
    private Long id;
    private String name;

    //getters and setter omitted for brevity
}

@Mapper
public interface CustomerMapper {
    // Here, source act as key. Mapstruct will try to use map.containsKey( "customerName" ) to check and then ex
    // map.get( "id" ) to get the value and assign to target
    @Mapping(target = "name", source = "customerName")
    Customer toCustomer(Map<String, String> map);
}
```

### Retrieving a mapper in another class to use its methods <a href="#retrieving-mapper" id="retrieving-mapper"></a>

#### Without using DI framework

```
CarMapper mapper = Mappers.getMapper( CarMapper.class );
```

But with this, we need to repeatedly instantiating new instances if we need to use it in several classes. To fix this, a mapper interface should define a member called `INSTANCE` which holds a single instance of the mapper type.

<pre class="language-java"><code class="lang-java"><strong>// Declaring an instance of a mapper (interface)
</strong><strong>@Mapper(componentModel = ComponentModel.SPRING)
</strong>public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    CarDto carToCarDto(Car car);
}

// Declaring an instance of a mapper (abstract class)
@Mapper
public abstract class CarMapper {

    public static final CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    CarDto carToCarDto(Car car);
}

// Usage in other classes
CarDto dto = CarMapper.INSTANCE.carToCarDto( car );

</code></pre>

#### Using DI framework

When using Spring Framework, it is recommended to obtain mapper objects via dependency injection and not via the `Mappers`class as described above.

```java
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface EventMapper {
...
}

// Usage
@RequiredArgsConstructor
@Component
public class SomeEventProcessor {
...
private final EventMapper eventMapper;
...
..
}
```

### Injection strategy <a href="#injection-strategy" id="injection-strategy"></a>

When using dependency injection, we can choose between field and constructor injection. This can be done by providing injection strategy via `@Mapper` or `@MapperConfig` annotation. Constructor injection is recommended to simplify testing. As per documentation, for abstract classes or decorators setter injection should be used.

```java
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface CarMapper {
    CarDto carToCarDto(Car car);
}
```

## Composition Mapping <a href="#mapping-composition" id="mapping-composition"></a>

MapStruct supports the use of meta annotations like @Retention. This allows `@Mapping` to be used on other (user defined) annotations for re-use purposes.

For example below. The `@ToTransactionHeader` assumes both target beans `TransactionEntity` and `PaymentEntity` have properties: `"id"`, `"creationDate"` and `"name"`

```java
@Retention(RetentionPolicy.CLASS)
@Mapping(target = "id", ignore = true)
@Mapping(target = "creationDate", expression = "java(new java.util.Date())")
@Mapping(target = "name", source = "groupName")
public @interface ToTransactionHeader { }

@Mapper
public interface TransactionMapper {

    TransactionMapper INSTANCE = Mappers.getMapper( TransactionMapper.class );

    @ToTransactionHeader
    @Mapping( target = "type", source = "type")
    TransactionEntity map(TransactionDto source);

    @ToTransactionHeader
    @Mapping( target = "accountId", source = "accountId")
    PaymentEntity map(PaymentDto source);
}
```

## Mapping collections <a href="#mapping-collections" id="mapping-collections"></a>

As per documentation, the mapping of collection types (`List`, `Set` etc.) is done in the same way as mapping bean types, i.e. by defining mapping methods with the required source and target types in a mapper interface

```java
@Mapper
public interface CarMapper {
    Set<String> integerSetToStringSet(Set<Integer> integers);

    List<CarDto> carsToCarDtos(List<Car> cars);

    CarDto carToCarDto(Car car);
}
```

{% hint style="info" %}
MapStruct has a `CollectionMappingStrategy`, with the possible values: `ACCESSOR_ONLY`, `SETTER_PREFERRED`, `ADDER_PREFERRED` and `TARGET_IMMUTABLE`. The option `DEFAULT` is synonymous to `ACCESSOR_ONLY`.

An `adder` method is typically used in case of generated (JPA) entities, to add a single element (entity) to an underlying collection. Invoking the adder establishes a parent-child relation between parent - the bean (entity) on which the adder is invoked - and its child(ren), the elements (entities) in the collection
{% endhint %}

### Mapping maps <a href="#mapping-maps" id="mapping-maps"></a>

```java
public interface SourceTargetMapper {
    @MapMapping(valueDateFormat = "dd.MM.yyyy")
    Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source);
}
```

### Implementation types used for collection mappings <a href="#implementation-types-for-collection-mappings" id="implementation-types-for-collection-mappings"></a>

As per documentation, when an iterable or map mapping method declares an interface type as return type, one of its implementation types will be instantiated in the generated code.

<table><thead><tr><th width="286">Interface type</th><th>Implementation type</th></tr></thead><tbody><tr><td><code>Iterable</code></td><td><code>ArrayList</code></td></tr><tr><td><code>Collection</code></td><td><code>ArrayList</code></td></tr><tr><td><code>List</code></td><td><code>ArrayList</code></td></tr><tr><td><code>Set</code></td><td><code>LinkedHashSet</code></td></tr><tr><td><code>SortedSet</code></td><td><code>TreeSet</code></td></tr><tr><td><code>NavigableSet</code></td><td><code>TreeSet</code></td></tr><tr><td><code>Map</code></td><td><code>LinkedHashMap</code></td></tr><tr><td><code>SortedMap</code></td><td><code>TreeMap</code></td></tr><tr><td><code>NavigableMap</code></td><td><code>TreeMap</code></td></tr><tr><td><code>ConcurrentMap</code></td><td><code>ConcurrentHashMap</code></td></tr><tr><td><code>ConcurrentNavigableMap</code></td><td><code>ConcurrentSkipListMap</code></td></tr></tbody></table>

## Mapping Streams <a href="#mapping-streams" id="mapping-streams"></a>

As per documentation, mapping of `java.util.Stream` is done in a similar way as the mapping of collection types, i.e. by defining mapping methods with the required source and target types in a mapper interface.

```java
@Mapper
public interface CarMapper {
    Set<String> integerStreamToStringSet(Stream<Integer> integers);

    List<CarDto> carsToCarDtos(Stream<Car> cars);

    CarDto carToCarDto(Car car);
}
```

## Mapping Values <a href="#mapping-enum-types" id="mapping-enum-types"></a>

### Mapping enum to enum types <a href="#mapping_enum_to_enum_types" id="mapping_enum_to_enum_types"></a>

```java
@Mapper
public interface OrderMapper {
    OrderMapper INSTANCE = Mappers.getMapper( OrderMapper.class );

    @ValueMappings({
        @ValueMapping(target = "SPECIAL", source = "EXTRA"),
        @ValueMapping(target = "DEFAULT", source = "STANDARD"),
        @ValueMapping(target = "DEFAULT", source = "NORMAL")
    })
    ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}
```

{% hint style="info" %}
As per documentation, MapStruct also support for mapping any remaining (unspecified) mappings to a default. This can be used only once in a set of value mappings and only applies to the source. It comes in two flavors: `<ANY_REMAINING>` and `<ANY_UNMAPPED>`. They cannot be used at the same time.

In case of source `<ANY_REMAINING>` MapStruct will continue to map a source enum constant to a target enum constant with the same name. The remainder of the source enum constants will be mapped to the target specified in the `@ValueMapping` with `<ANY_REMAINING>` source.

MapStruct will **not** attempt such name based mapping for `<ANY_UNMAPPED>` and directly apply the target specified in the `@ValueMapping` with `<ANY_UNMAPPED>` source to the remainder.

MapStruct is able to handle `null` sources and `null` targets by means of the `<NULL>` keyword.

In addition, the constant value `<THROW_EXCEPTION>` can be used for throwing an exception for particular value mappings.
{% endhint %}

```java
@Mapper
public interface SpecialOrderMapper {

    SpecialOrderMapper INSTANCE = Mappers.getMapper( SpecialOrderMapper.class );

    // MapStruct would have refrained from mapping the RETAIL and B2B when <ANY_UNMAPPED> was used instead of <ANY_REMAINING>
    @ValueMappings({
        @ValueMapping( source = MappingConstants.NULL, target = "DEFAULT" ),
        @ValueMapping( source = "STANDARD", target = MappingConstants.NULL ),
        @ValueMapping( source = MappingConstants.ANY_REMAINING, target = "SPECIAL" )
    })
    ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}
```

```java
@Mapper
public interface SpecialOrderMapper {

    SpecialOrderMapper INSTANCE = Mappers.getMapper( SpecialOrderMapper.class );

    @ValueMappings({
        @ValueMapping( source = "STANDARD", target = "DEFAULT" ),
        @ValueMapping( source = "C2C", target = MappingConstants.THROW_EXCEPTION )
    })
    ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}
```

### Mapping enum-to-String or String-to-enum <a href="#mapping_enum_to_string_or_string_to_enum" id="mapping_enum_to_string_or_string_to_enum"></a>

MapStruct supports enum to a String mapping on the similar lines.

### Custom name transformation <a href="#custom_name_transformation" id="custom_name_transformation"></a>

As per documentation, when no `@ValueMapping`(s) are defined then each constant from the source enum is mapped to a constant with the same name in the target enum type. However, there are cases where the source enum needs to be transformed before doing the mapping. E.g. a suffix needs to be applied to map from the source into the target enum.

MapStruct provides the following enum name transformation strategies:

* *suffix* - Applies a suffix on the source enum
* *stripSuffix* - Strips a suffix from the source enum
* *prefix* - Applies a prefix on the source enum
* *stripPrefix* - Strips a prefix from the source enum
* *case* - Applies case transformation to the source enum. Supported *case* transformations are:
  * *upper* - Performs upper case transformation to the source enum
  * *lower* - Performs lower case transformation to the source enum
  * *capital* - Performs capitalisation of the first character of every word in the source enum and everything else to lowercase. A word is split by "\_"

```java
@Mapper
public interface CheeseMapper {
    CheeseMapper INSTANCE = Mappers.getMapper( CheeseMapper.class );

    @EnumMapping(nameTransformationStrategy = "suffix", configuration = "_TYPE")
    CheeseTypeSuffixed map(CheeseType cheese);

    @InheritInverseConfiguration
    CheeseType map(CheeseTypeSuffix cheese);
}
```

## Object factories <a href="#object-factories" id="object-factories"></a>

By default, the generated code for mapping one bean type into another or updating a bean will call the default constructor to instantiate the target type. Alternatively, Mapstruct supports custom object factories which will be invoked to obtain instances of the target type.

```java
public class DtoFactory {
     public CarDto createCarDto() {
         return // ... custom factory logic
     }
}

public class EntityFactory {
     public <T extends BaseEntity> T createEntity(@TargetType Class<T> entityClass) {
         return // ... custom factory logic
     }
}

@Mapper(uses= { DtoFactory.class, EntityFactory.class } )
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    CarDto carToCarDto(Car car);

    Car carDtoToCar(CarDto carDto);
}

@Mapper(uses = { DtoFactory.class, EntityFactory.class, CarMapper.class } )
public interface OwnerMapper {

    OwnerMapper INSTANCE = Mappers.getMapper( OwnerMapper.class );

    void updateOwnerDto(Owner owner, @MappingTarget OwnerDto ownerDto);

    void updateOwner(OwnerDto ownerDto, @MappingTarget Owner owner);
}
```

## Reusing mapping configurations <a href="#reusing_mapping_configurations" id="reusing_mapping_configurations"></a>

### Mapping configuration inheritance <a href="#mapping-configuration-inheritance" id="mapping-configuration-inheritance"></a>

Method-level configuration annotations such as `@Mapping`, `@BeanMapping`, `@IterableMapping`, etc., can be **inherited**from one mapping method to a **similar** method using the annotation `@InheritConfiguration`

```java
@Mapper
public interface CarMapper {
    @Mapping(target = "numberOfSeats", source = "seatCount")
    Car carDtoToCar(CarDto car);

    @InheritConfiguration
    void carDtoIntoCar(CarDto carDto, @MappingTarget Car car);
}
```

### Inverse mappings <a href="#inverse-mappings" id="inverse-mappings"></a>

In case of bi-directional mappings, e.g. from entity to DTO and from DTO to entity, the mapping rules for the forward method and the reverse method are often similar and can simply be inversed by switching `source` and `target`

```java
@Mapper
public interface CarMapper {

    @Mapping(target = "seatCount", source = "numberOfSeats")
    CarDto carToDto(Car car);

    @InheritInverseConfiguration
    @Mapping(target = "numberOfSeats", ignore = true)
    Car carDtoToCar(CarDto carDto);
}
```

### Shared configurations <a href="#shared-configurations" id="shared-configurations"></a>

MapStruct offers the possibility to define a shared configuration by pointing to a central interface annotated with `@MapperConfig`. For a mapper to use the shared configuration, the configuration interface needs to be defined in the `@Mapper#config` property. Attributes specified in `@Mapper` take precedence over the attributes specified via the referenced configuration class

```java
@MapperConfig(
    uses = CustomMapperViaMapperConfig.class,
    unmappedTargetPolicy = ReportingPolicy.ERROR
)
public interface CentralConfig {
}

@Mapper(config = CentralConfig.class, uses = { CustomMapperViaMapper.class } )
// Effective configuration:
// @Mapper(
//     uses = { CustomMapperViaMapper.class, CustomMapperViaMapperConfig.class },
//     unmappedTargetPolicy = ReportingPolicy.ERROR
// )
public interface SourceTargetMapper {
  ...
}
```

## Customizing mappings <a href="#customizing_mappings" id="customizing_mappings"></a>

If we need to apply custom logic before or after certain mapping methods, MapStruct provides two ways for doing so: decorators which allow for a type-safe customization of specific mapping methods and the before-mapping and after-mapping lifecycle methods which allow for a generic customization of mapping methods with given source or target types.

### Mapping customization with before-mapping and after-mapping methods <a href="#customizing-mappings-with-before-and-after" id="customizing-mappings-with-before-and-after"></a>

```java
@Mapper
public abstract class VehicleMapper {
    @BeforeMapping
    protected void flushEntity(AbstractVehicle vehicle) {
        // I would call my entity manager's flush() method here to make sure my entity
        // is populated with the right @Version before I let it map into the DTO
    }

    @AfterMapping
    protected void fillTank(AbstractVehicle vehicle, @MappingTarget AbstractVehicleDto result) {
        result.fuelUp( new Fuel( vehicle.getTankCapacity(), vehicle.getFuelType() ) );
    }

    public abstract CarDto toCarDto(Car car);
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.pranaypourkar.co.in/the-programmers-guide/spring/utilities-and-libraries/mapstruct-mapper.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
