如何在 mapstruct 中使用来自不同类的另一个映射

use*_*655 2 java spring java-8 mapstruct

我想将模型对象映射到 dto 模型。我已经有一个对象的映射器。如何在另一个类中的另一个映射器中重用这个映射器?

我有以下作为模型

    @Getter
    @AllArgsConstructor
    @ToString
    public class History {

      @JsonProperty("identifier")
      private final Identifier identifier;

    @JsonProperty("submitTime")
    private final ZonedDateTime submitTime;

    @JsonProperty("method")
    private final String method;

    @JsonProperty("reason")
    private final String reason;

    @JsonProperty("dataList")
    private final List<Data> dataList;
   }

     @DynamoDBTable(tableName = "history")
     @Data
     @NoArgsConstructor
     public class HistoryDynamo {
        @DynamoDBRangeKey(attributeName = "submitTime")
        @DynamoDBTypeConverted(converter = ZonedDateTimeType.Converter.class)
        private ZonedDateTime submitTime;

        @DynamoDBAttribute(attributeName = "identifier")
        @NonNull
        private Identifier identifier;

        @DynamoDBAttribute(attributeName = "method")
        private String method;

         @DynamoDBAttribute(attributeName = "reason")
         private String reason;

         @DynamoDBAttribute(attributeName = "dataList")
         private List<Data> dataList;
     }

        @Data
        @DynamoDBDocument
        @NoArgsConstructor
        public class Identifier implements Serializable {
    
            @DynamoDBAttribute(attributeName = "number")
            private String number;
    
        @DynamoDBAttribute(attributeName = "cityCode")
        @NonNull
        private String cityCode;
    
        @DynamoDBAttribute(attributeName = "countryCode")
        @NonNull
        private String countryCode;
    
        @DynamoDBTypeConverted(converter = LocalDateType.Converter.class)
        private LocalDate mydate;
    }
    
         @Data
         @EqualsAndHashCode
         @NoArgsConstructor
         @RequiredArgsConstructor
         @JsonInclude(JsonInclude.Include.NON_NULL)
         public class Identifier implements Serializable {
    
        @NonNull
        @lombok.NonNull
        @NotNull
        private String number;
    
        @NonNull
        @lombok.NonNull
        @NotNull
        private City city;
    
        @NonNull
        @lombok.NonNull
        @NotNull
        private Country country;
    
        @JsonDeserialize(using = LocalDateDeserializer.class)
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'Z'")
        @DateTimeFormat(pattern = "yyyy-MM-dd'Z'")
        @NonNull
        @lombok.NonNull
        @NotNull
        private LocalDate mydate;
    }
Run Code Online (Sandbox Code Playgroud)

这是我的映射

    @Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.WARN, injectionStrategy = InjectionStrategy.CONSTRUCTOR, nullValueMappingStrategy = NullValueMappingStrategy.RETURN_NULL)
    public interface IdentifierMapper {
    
        IdentifierMapper MAPPER = Mappers.getMapper(IdentifierMapper.class);
    
    
        @Mappings({@Mapping(source = "identifier.number", target = "number"),
                   @Mapping(source = "identifier.city.code", target = "cityCode"),
                   @Mapping(source = "identifier.country.code", target = "countryCode"),
                   @Mapping(source = "identifier.mydate", target = "mydate")})
        @Named("toIdentifierDynamo")
        myproject.entity.dynamo.Identifier toIdentifierDynamo(myproject.model.Identifier identifier);
    }
    
    @Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.WARN, injectionStrategy = InjectionStrategy.CONSTRUCTOR,
            nullValueMappingStrategy = NullValueMappingStrategy.RETURN_NULL, uses = {IdentifierMapper.class})
    public interface HistoryMapper {
    
        HistoryMapper MAPPER = Mappers.getMapper(HistoryMapper.class);
    
        @Mappings({@Mapping(source = "identifier", target = "identifier", qualifiedByName = "toIdentifierDynamo"),
                  @Mapping(source = "method", target = "method"),
                  @Mapping(source = "reason", target = "reason"),
                  @Mapping(source = "timestamp", target = "timestamp")})
        HistoryDynamo toHistoryDynamo(History history);
    }
Run Code Online (Sandbox Code Playgroud)

我想将 History 映射到 HistoryDynamo 并重用 IdentifierMapper 来映射 HistoryDynamo 中的对象之一。如何在 toHistoryDynamo 中使用 toIdentifierDynamo?

Rak*_*han 10

使用 spring 依赖可以轻松注入

private final HistoryMapper 
 historyMapper;
Run Code Online (Sandbox Code Playgroud)

此外,对于目标和源中具有相同名称的字段,无需使用@Mapping,因此在上面的情况下,下面的映射器定义足以实现所需的结果。

@Mapper(
    componentModel = "spring",
    injectionStrategy = InjectionStrategy.CONSTRUCTOR,
    uses = {IdentifierMapper.class})
public interface HistoryMapper {

  HistoryDynamo toHistoryDynamo(History history);

} 
Run Code Online (Sandbox Code Playgroud)

请参阅此处的 github 示例https://github.com/rakesh-singh-samples/map-struct-samples/tree/stack-question-60523230/src/sample/mapstruct/mapper

  • 好的,我明白了,我的 IdentifierMapper 缺少 @Mapper(componentModel = "spring") 配置。 (2认同)

小智 5

  • 首先,您不必在 Spring 中创建实例。你可以只自动装配你的映射器。
  • 其次,@Mapping如果每个字段具有相同的名称,则不必为每个字段提供注释。Mapstruct 将为您完成。
  • 你的问题可以用做usesMapStruct的参数映射器 HistoryMapper可能在@Mapper标注的参数uses = IdentifierMapper.class。它将自动连接IdentifierMapperHistoryMapper. 默认情况下,它将通过字段执行。您也可以在参数中更改它:injectionStrategy = InjectionStrategy.CONSTRUCTOR并且可能就足够了,因为您具有相同的字段名称(标识符)并且 MapStruct 应该意识到应该使用IdentifierMapper

  • 您可以在此处添加一些代码示例以使这个答案更清楚吗? (4认同)
  • 嗯,我正在尝试在我的实现中实现上述内容。我确实看到在主映射器的实现中创建了映射器,但它缺少 Autowired 注释。我是否缺少一些如何在实现映射器上获取该注释的信息,因为它会在测试中导致 NPE (2认同)