MapStruct 无法找到泛型 Set 属性的成员。

huangapple go评论86阅读模式
英文:

MapStruct cannot find members from generic Set property

问题

我开始使用 MapStruct `1.4.0.CR1` 版本。我还在使用 Gradle:

```groovy
dependencies {
  annotationProcessor("org.mapstruct:mapstruct-processor:${project.property("mapstruct.version")}")

  implementation("org.mapstruct:mapstruct:${project.property("mapstruct.version")}")
}

我有一些 JPA 实体需要进行映射:

public class Exam implements Serializable {
  // 更多类成员在这里

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "exam", orphanRemoval = true)
  private Set<Scan> scans;

  public Exam() { } // ...JPA 需要的无参构造函数

  public Exam(final Builder builder) {
    // ...设置其余内容
    scans = builder.scans;
  }

  // 这里有 getters(没有 setters)、hashCode、equals,以及 builder
}
public class Scan implements Serializable {
  // 更多类成员在这里

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "scan", orphanRemoval = true)
  private Set<Alarm> alarms;

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "scan", orphanRemoval = true)
  private Set<Isotope> isotopes;

  protected Scan() { } // ...JPA 需要的无参构造函数

  public Scan(final Builder builder) {
    // ...设置其余内容
    alarms = builder.alarms;
    isotopes = builder.isotopes;
  }

  // 这里有 getters(没有 setters)、hashCode、equals,以及 builder
}

我有类似的映射类,但它们的字段/成员没有 JPA 实体多,而且它们位于一个完全不同的子系统中(因此需要映射)。问题是 MapStruct 告诉我在 Scan 中没有 isotopesjava: 源参数中不存在名为 "scans.isotopes" 的属性。是否意味着 "scans.empty"

基本上,在(新的)映射的 Exam 类中,并不是通过一个 scansSet 包含了 isotopesalarms。这是我的 ExamMapper

@FunctionalInterface
@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface ExamMapper {
  // @Mapping(source = "scans.alarms", target = "alarms")
  @Mapping(source = "scans.isotopes", target = "isotopes")
  Exam valueFrom(tld.domain.Exam entity);
}

是否有办法实现这一点?我认为这可能是微不足道的,但我对 MapStruct 还相对新手;)


<details>
<summary>英文:</summary>

I started using MapStruct `1.4.0.CR1`. I&#39;m also using Gradle:

```groovy
dependencies {
  annotationProcessor(&quot;org.mapstruct:mapstruct-processor:${project.property(&quot;mapstruct.version&quot;)}&quot;)

  implementation(&quot;org.mapstruct:mapstruct:${project.property(&quot;mapstruct.version&quot;)}&quot;)
}

I have some JPA entities I'm trying to map:

public class Exam implements Serializable {
  // More class members here

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = &quot;exam&quot;, orphanRemoval = true)
  private Set&lt;Scan&gt; scans;

  public Exam() { } // ...no-argument constructor required by JPA

  public Exam(final Builder builder) {
    // ...set the rest also
    scans = builder.scans;
  }

  // getters (no setters), hashCode, equals, and builder here
}
public class Scan implements Serializable {
  // More class members here

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = &quot;scan&quot;, orphanRemoval = true)
  private Set&lt;Alarm&gt; alarms;

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = &quot;scan&quot;, orphanRemoval = true)
  private Set&lt;Isotope&gt; isotopes;

  protected Scan() { } // ...no-argument constructor required by JPA

  public Scan(final Builder builder) {
    // ...set the rest also
    alarms = builder.alarms;
    isotopes = builder.isotopes;
  }

  // getters (no setters), hashCode, equals, and builder here
}

I have similar classes for mapping, but they don't have as many fields/members as the JPA entities, moreover, they are on a completely different sub-system (hence the mapping). The problem is that MapStruct is telling me there are no isotopes within Scans: java: No property named &quot;scans.isotopes&quot; exists in source parameter(s). Did you mean &quot;scans.empty&quot;?.

Basically, isotopes and alarms are not contained within a Set of scans in the (new) mapped Exam class. This is my ExamMapper:

@FunctionalInterface
@Mapper(componentModel = &quot;spring&quot;, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface ExamMapper {
  // @Mapping(source = &quot;scans.alarms&quot;, target = &quot;alarms&quot;)
  @Mapping(source = &quot;scans.isotopes&quot;, target = &quot;isotopes&quot;)
  Exam valueFrom(tld.domain.Exam entity);
}

Is there a way to accomplish this? I think this may be trivial, but I'm fairly new to MapStruct MapStruct 无法找到泛型 Set 属性的成员。

答案1

得分: 1

@Mapping(source = "scans", target = "isotopes")
Exam valueFrom(tld.domain.Exam entity);

Isotope valueFrom(tld.domain.Isotope isotope);

default Set<Isotope> flatMapIsotopes(Set<Scan> scans) {
  return scans.stream()
      .flatMap(scan -> scan.getIsotopes().stream())
      .map(this::valueFrom)
      .collect(Collectors.toSet());
}
英文:

The source and target attributes of the @Mapping can only reference bean properties.

This means that when using scans.isotopes, it will look for a property isotopes in Set&lt;Scan&gt; and thus the compile error.

In order to solve this you'll need to provide some custom mappings. From what I can understand you will need to do flat mapping here as well. The reason for that is that you have multiple scans, and each scan has multiple isotopes. You need to gather all of that and map it into a single collection.

One way to achieve this is in the following way:

@Mapper(componentModel = &quot;spring&quot;, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface ExamMapper {

  @Mapping(source = &quot;scans&quot;, target = &quot;isotopes&quot;)
  Exam valueFrom(tld.domain.Exam entity);

  Isotope valueFrom(tld.domain.Isotope isotope);

  default Set&lt;Isotope&gt; flatMapIsotopes(Set&lt;Scan&gt; scans) {
    return scans.stream()
        .flatMap(scan -&gt; scan.getIsotopes().stream())
        .map(this::valueFrom)
        .collect(Collectors.toSet());
  }
 
}

huangapple
  • 本文由 发表于 2020年9月15日 21:45:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/63903281.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定