mapstruct / mapstruct/mapstruct

Map with immutable target

Open
#2,155 7 comments 8 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature up-for-grabs
Dominant language
Java
Stars
7.7k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Description

(not really a bug, but more of an improvement)

Mapstruct apparently offers no way to map with an immutable "target".

**Context:**
We have a CarDto and a Car that are both immutable and use a builder generated via Lombok

```java
@Value
@Builder(toBuilder=true)
class Car {
final String color;
final double price;
final int hiddenField;
}

@Value
@Builder(toBuilder=true)
class CarDto {
final String color;
final double price;
}
```
A standard mapping like
```java
@Mapper
class CarMapper {
Car toEntity(CarDto dto);
}
```
works as intended. The generated mapper creates a new CarBuilder, fill the fields and then return the built entity

**The issue:**
As we have `hiddenField` which is not present in the DTO, when we have an API call to update the `Car` entity we need to map the given DTO to the existing entity to preserve the value of the field.

So naively I'd do:
```java
@Mapper
class CarMapper {
Car toEntity(CarDto dto, @MappingTarget Car existingCar);
}
```

However mapstruct doesn't seem to support this use case with an immutable target. And as the documentation clearly states:
> you may also set the method’s return type to the type of the target parameter, which will cause the generated implementation to update the passed mapping target and return it as well.

So yeah, it does not create a copy of the `Car`, it tries to update the given one... And as there are no setter, it doesn't do anything.

As mapstruct supports the builder pattern for regular mapping, it'd be great if mapstruct could get the existing entity, call `toBuilder` on it and then do the mapping as usual.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with MapStruct's existing builder support and @MappingTarget handling, using the Car and CarDto examples in this issue as the expected scenario. Determine how an immutable target could be copied through toBuilder(), mapped, and returned while preserving fields absent from the source; done means this behavior is supported without setters.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.