英文:
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
中没有 isotopes
:java: 源参数中不存在名为 "scans.isotopes" 的属性。是否意味着 "scans.empty"
。
基本上,在(新的)映射的 Exam
类中,并不是通过一个 scans
的 Set
包含了 isotopes
和 alarms
。这是我的 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'm also using Gradle:
```groovy
dependencies {
annotationProcessor("org.mapstruct:mapstruct-processor:${project.property("mapstruct.version")}")
implementation("org.mapstruct:mapstruct:${project.property("mapstruct.version")}")
}
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 = "exam", orphanRemoval = true)
private Set<Scan> 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 = "scan", orphanRemoval = true)
private Set<Alarm> alarms;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "scan", orphanRemoval = true)
private Set<Isotope> 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 Scan
s: java: No property named "scans.isotopes" exists in source parameter(s). Did you mean "scans.empty"?
.
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 = "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);
}
Is there a way to accomplish this? I think this may be trivial, but I'm fairly new to MapStruct
答案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<Scan>
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 = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface ExamMapper {
@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());
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论