@AfterMapping 方法未在生成的 class 中调用

@AfterMapping mehod is not called in generated class

我正在尝试自定义映射,使用字符串来确定对象属性,所以我这样写:

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public abstract class ProductMapper {

public abstract ProductInput asProductInputFromIdentifier(String identifier);

@AfterMapping
protected void determineIdentifier(String identifier, @MappingTarget ProductInput out) {
    if (StringUtils.contains(identifier, '?')) {
        out.setExternalId(identifier);
    } else {
        out.setInernalId(identifier);
    }
}
}

生成的 class 不会调用 determineIdentifier 方法。我通过在 asProductInputFromIdentifier 方法上直接使用 Java 表达式找到了另一个解决方案,但我真的想使用 @AfterMapping[=22= 编写清晰的代码].

@Mapping(target = "externalId", expression = "java( org.apache.commons.lang3.StringUtils.contains(identifier, '|') ? identifier : null )")
@Mapping(target = "internalId", expression = "java( !org.apache.commons.lang3.StringUtils.contains(identifier, '|') ? identifier : null )")
public abstract ProductInput asProductDetailInputFromIdentifier(String identifier);

我不明白为什么它不起作用是因为我的方法参数中没有对象吗?

带有 @AfterMapping 的方法将在 map 方法的末尾执行,它应该具有与 map 方法相同的输入参数,例如下面的示例

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

  HistoryDynamo toHistoryDynamo(History history);

  @AfterMapping
  default void changeReason(History history) {
    System.out.println(history.getReason());
  }
}

参考 github 相同的工作样本 https://github.com/rakesh-singh-samples/map-struct-samples/tree/stack-question-60523230/src/sample/mapstruct/mapper

MapStruct 不知道如何从 String 映射到 ProductInput 在你的情况下我建议你自己实现映射方法。

例如

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public abstract class ProductMapper {

    public ProductInput asProductInputFromIdentifier(String identifier) {
        ProductInput out = new ProductInput();
        if (StringUtils.contains(identifier, '?')) {
            out.setExternalId(identifier);
        } else {
            out.setInernalId(identifier);
        }
        return out;
    }
}

没有必要使用生命周期回调或特殊的 @Mapping 注释来执行此示例中的简单映射。

为了解决这个问题,我将 ProductInput 添加到抽象方法参数中,如下所示(这不是要求)。正如@Rakesh 在他上面的回答中所解释的那样 带有@AfterMapping 的方法将在 map 方法的末尾执行,它应该具有与 map 方法相同的输入参数,但它可能会让其他人对他们的情况感兴趣:

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public abstract class ProductMapper {

   public abstract ProductInput asProductInputFromIdentifier(String identifier, ProductInput out);

   @AfterMapping
   protected void determineIdentifier(String identifier, @MappingTarget ProductInput out) {
      if (StringUtils.contains(identifier, '?')) {
          out.setExternalId(identifier);
      } else {
          out.setInernalId(identifier);
       }
    }
}

但在我的例子中,我使用了 builder = @Builder(disableBuilder = true) 来关闭 MapStruct 中的“builders”,因为它可以帮助某人 ;) Mapstruct Builder 现在生成的 MapperImpl 调用带注释的 @AfterMapping 方法。