mapstruct / mapstruct/mapstruct

using @MappingTarget with @Default constructor annotated member class

未關閉
#2,178 3 則留言 0 個 reaction 已指派 1 人 在 GitHub 檢視

@sjaakd 已經在處理了。

開始於 2020年8月21日。

feature for:team-discussion
主要語言
Java
星號
7.7k
分支
1.1k
PR 合併指標
30 天內沒有已合併 PR

描述

Mapping method with @MappingTarget generates code that tries to alter immutable member instead of setting a new instance.

Example:
If I have a class with a constructor injected member:
```
public class DemonstratorTarget {
private DemonstratorTargetEmbedded embedded;
@Default
public DemonstratorTarget(DemonstratorTargetEmbedded embedded) { this.embedded = embedded; }
public DemonstratorTargetEmbedded getEmbedded() { return embedded; }
public void setEmbedded(DemonstratorTargetEmbedded embedded) { this.embedded = embedded; }
}
```
with a supposedly immutable member class:
```
public class DemonstratorTargetEmbedded {
private String version;
private Map metadata = new HashMap<>();
public DemonstratorTargetEmbedded() { }
@Default
public DemonstratorTargetEmbedded(String version, Map metadata) {
this.version = version;
this.metadata = metadata;
}
public String getVersion() { return version; }
public Map getMetadata() { return metadata; }
}
```
and use it in a mapper as `@MappingTarget`:
```
@Mapper
public interface DemonstratorMapperBroken {
void updateTarget(@MappingTarget DemonstratorTarget target, DemonstratorSource source);
}
```
The resulting mapper will not call `target.setEmbedded([newly created instance])` but tries to alter the member:
```
mappingTarget.getMetadata().clear();
Map map = demonstratorSourceEmbedded.getMetadata();
if ( map != null ) {
mappingTarget.getMetadata().putAll( map );
}
```
This of course fails in the example above, because there is no setter for `version`.

Now if I change the mapper to look like this (added a mapping method, did not change the original one):
```
@Mapper
public interface DemonstratorMapperWorking {
void updateTarget(@MappingTarget DemonstratorTarget target, DemonstratorSource source);
DemonstratorTargetEmbedded toTargetEmbedded(DemonstratorSourceEmbedded gender);
}
```
...the mapper works as expected:
```
target.setEmbedded( toTargetEmbedded( source.getEmbedded() ) );
[...]
DemonstratorTargetEmbedded demonstratorTargetEmbedded = new DemonstratorTargetEmbedded( version, metadata );
```

I am unsure if this is expected behaviour. Is there a way to circumvent this without adding a method like `toTargetEmbedded`?

I created a demonstrator:
1. `git clone -b mapstruct-constructor-mapping https://github.com/mickroll/demonstrator.git`
2. `cd demonstrator`
3. `mvn clean install`

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。