使用 java 代码而不是 mapstruct 表达式

use java code instead of mapstruct expression

我正在学习使用MapStruct

我有以下自定义映射配置,它以这种方式将来自 JPA 实体的 List 映射到 DTO String

@Mapper(componentModel = "spring")
public interface StatusMapper {

    @Mapping(target = "statusCode",
            expression = "java(entity.getStatuses().get(entity.getStatuses().size() - 1).getStatus())")
    @Mapping(target = "details",
            expression = "java(entity.getStatuses().get(entity.getStatuses().size() - 1).getMessage())")
    StatusResponse map(MyEntity entity);
}

我对这个解决方案的问题是 expression 中的 Java 代码实际上是一个字符串,而 IDE(例如 IntelliJ)没有检查这个“java" 代码。 也许重构后这段代码将不再起作用,因为我重命名了相关字段。

如果我在表达式中添加一个 null 检查,那么这段代码将会更长,而更长的代码可能会有更多的拼写错误。

我可以在这里写一个真正的 java 代码而不是使用这个 Java 表达式字符串吗?

记住MapStruct是注解处理器,写在expression中的表达式会在生成的Javaclass中一一对应。因此,进行重构会导致编译错误。

话虽如此,但有一个替代解决方案。

@Mapper(componentModel = "spring")
public interface StatusMapper {

    @Mapping(target = "statusCode", source = "statuses", qualifiedByName = "statusesStatus")
    @Mapping(target = "details", source = "statuses", qualifiedByName = "statusesMessage")
    StatusResponse map(MyEntity entity);

    @Named("statusesStatus")
    default String extractStatus(Collection<Status> statuses) {
        return statuses != null && statuses.isEmpty() ? statuses.get(statuses.get() - 1).getStatus() : null;
    }

    @Named("statusesMessage")
    default String extractStatusMessage(Collection<Status> statuses) {
        return statuses != null && !statuses.isEmpty() ?  statuses.get(statuses.get() - 1).getMessage() : null;
    }
}

这样做将确保 MapStruct 使用您定义的自定义方法。


另一个可能不错的解决方案(MapStruct 中尚不存在)并且有一个开放的功能请求是 Allowing indexing for object list

可能的解决方案如下所示:

@Mapper(componentModel = "spring")
public interface StatusMapper {

    @Mapping(target = "statusCode", source = "statuses[-1].status")
    @Mapping(target = "details", source = "statuses[-1].message")
    StatusResponse map(MyEntity entity);
}

如果您对此感兴趣,我建议您就此问题进行投票。