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

MapStruct: Map multiple sources from multiple objects to one target

我要映射以下类

class Schedule {
    ZoneId timezoneId;
    List<AvailabilityRule> rules;
}
class AvailabilityRule {
    long startEpoch;
    long endEpoch;
}

这些 类.

class ScheduleDTO {
    String timezone;
    List<AvailabilityRuleDTO> rules;
}
class AvailabilityRuleDTO {
    ZonedDateTime startTime;
    ZonedDateTime endTime;
}

计算startTime需要timezoneIdstartEpoch

Instant instant = Instant.ofEpochMilli(startEpoch);
ZonedDateTime zonedDateTime = instant.atZone(timezoneId);
        

如何使用 mapstruct 实现此目的?

我想要的伪代码

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

将两个对象映射为一个对象的映射器接口如下:

@Mapper
public interface CalculateTimeMapper{
     @Mapping(source = "schedule.timezoneId", target = "timezone")
     @Mapping(source = "availabilityRule.startEpoch", target = "startTime")
     AvailabilityRuleDTO toAvailabilityRuleDTO(AvailabilityRule
                                            availabilityRule, Schedule schedule);
}

您可以参考以下内容:

https://www.tutorialspoint.com/tutorial_view.htm?cid=mapstruct&pid=mapstruct_mapping_multiple.htm

这可以通过多种方式完成。您在下方看到 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;
    }

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

这里使用

@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;
    }

包括时间表在内的完整映射器


@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();
    }
}