将多个对象的多个源映射到一个目标

dup*_*143 10 java object-object-mapping mapstruct

我想映射以下类

class Schedule {
    ZoneId timezoneId;
    List<AvailabilityRule> rules;
}
Run Code Online (Sandbox Code Playgroud)
class AvailabilityRule {
    long startEpoch;
    long endEpoch;
}
Run Code Online (Sandbox Code Playgroud)

到这些课程。

class ScheduleDTO {
    String timezone;
    List<AvailabilityRuleDTO> rules;
}
Run Code Online (Sandbox Code Playgroud)
class AvailabilityRuleDTO {
    ZonedDateTime startTime;
    ZonedDateTime endTime;
}
Run Code Online (Sandbox Code Playgroud)

timezoneId计算时startEpoch需要和startTime。

Instant instant = Instant.ofEpochMilli(startEpoch);
ZonedDateTime zonedDateTime = instant.atZone(timezoneId);
        
Run Code Online (Sandbox Code Playgroud)

我如何使用mapstruct 来实现这一点?

我想要的伪代码

@Mapping(source = {"startEpoch", "timezoneId"}, target = "startTime", qualifiedByName = "epochToString")
AvailabilityRuleDTO toAvailabilityRuleDTO(AvailabilityRule
                                            availabilityRule, Schedule schedule);
Run Code Online (Sandbox Code Playgroud)

Ben*_*eld 18

这可以通过多种方式来完成。下面你会看到 2 个选项。他们做同样的事情,只有一个人使用qualifiedByName,而另一个人使用expression。根据您的需要,其中一种可能比另一种更适合。

使用mapstruct找到的自定义方法

qualifiedByName必需的,因为否则 mapstruct 不知道使用哪个方法。

    @Mapping(source = ".", target = "startTime", qualifiedByName = "startTime")
    @Mapping(source = ".", target = "endTime", qualifiedByName = "endTime")
    AvailabilityRuleDTO toAvailabilityRuleDTO(AvailabilityRule availabilityRule, @Context Schedule schedule);

    @Named("startTime")
    protected ZonedDateTime startTime(AvailabilityRule availabilityRule, @Context Schedule schedule) {
        return convertTime(availabilityRule.startEpoch, schedule.timezoneId);
    }

    @Named("endTime")
    protected ZonedDateTime endTime(AvailabilityRule availabilityRule, @Context Schedule schedule) {
        return convertTime(availabilityRule.endEpoch, schedule.timezoneId);
    }

    private ZonedDateTime convertTime(long epoch, String timezoneId) {
        Instant instant = Instant.ofEpochMilli(epoch);
        ZonedDateTime time = LocalDateTime.from(instant).atZone(timezoneId);
        return time;
    }

Run Code Online (Sandbox Code Playgroud)

使用由表达式配置的自定义方法

@Named此处用于防止 mapstruct 意外使用此方法进行其他映射操作。没有它它很可能仍然有效。

    @Mapping(target = "startTime", expression = "java(convertTime(availabilityRule.startEpoch, schedule.timezoneId))" )
    @Mapping(target = "endTime", expression = "java(convertTime(availabilityRule.endEpoch, schedule.timezoneId))" )
    AvailabilityRuleDTO toAvailabilityRuleDTO(AvailabilityRule
                                                availabilityRule, Schedule schedule);


    @Named("time")
    protected ZonedDateTime convertTime(long epoch, String timezoneId) {
        Instant instant = Instant.ofEpochMilli(epoch);
        ZonedDateTime time = LocalDateTime.from(instant).atZone(timezoneId);
        return time;
    }
Run Code Online (Sandbox Code Playgroud)

完整的地图绘制器,包括时间表


@Mapper
public abstract class ScheduleMapper {
    @Mapping(target = "timezone", source = "timezoneId")
    @Mapping(target = "rules", expression = "java(toAvailabilityRuleDTOs(schedule.getRules(), schedule))")
    abstract ScheduleDTO toScheduleDTO(Schedule schedule);

    @Named("rules")
    abstract List<AvailabilityRuleDTO> toAvailabilityRuleDTOs(List<AvailabilityRule> rules, @Context Schedule schedule);

    @Mapping(target = "startTime", expression = "java(convertTime(availabilityRule.startEpoch, schedule.timezoneId))")
    @Mapping(target = "endTime", expression = "java(convertTime(availabilityRule.endEpoch, schedule.timezoneId))")
    abstract AvailabilityRuleDTO toAvailabilityRuleDTO(AvailabilityRule availabilityRule, @Context Schedule schedule);

    @Named("time")
    protected ZonedDateTime convertTime(long epoch, ZoneId timezoneId) {
        Instant instant = Instant.ofEpochMilli(epoch);
        ZonedDateTime time = LocalDateTime.from(instant).atZone(timezoneId);
        return time;
    }

    String map(ZoneId zoneId) {
        return zoneId == null ? null : zoneId.getId();
    }
}
Run Code Online (Sandbox Code Playgroud)