【问题标题】:Can't get MapStruct to work with Enum Inheritance & @TargetTytpe无法让 MapStruct 与 Enum Inheritance 和 @TargetTytpe 一起使用
【发布时间】:2021-08-16 07:20:29
【问题描述】:

这是我的示例设置:

interface EnumMessage {
  boolean carrier(String message);

  String getValue();

  default String getMessage() {
    return getValue().toUpperCase();
  }
}

enum EnumMessageA implements EnumMessage {
  GREAT("You are doing great"),
  GOOD("You are doing good"),
  OK("You are doing ok");

  private String value;

  EnumMessageA(final String value) {
    this.value = value;
  }

  @Override
  public String getValue() {
    return value;
  }

  @Override
  public boolean carrier(final String message) {
    return this.value.equals(message);
  }
}

class SourceX {
  public String name;
  public String message;
}

class TargetX {
  public String name;
  public EnumMessageA messageA;
}

@Mapper
interface EnumMapper {
  EnumMapper INSTANCE = Mappers.getMapper(EnumMapper.class);

  @Mapping(source = "message", target = "messageA", qualifiedByName = "stringToEnum")
  TargetX toTarget(SourceX source);

  @Mapping(source = "messageA", target = "message", qualifiedByName = "enumToString")
  SourceX toSource(TargetX target);

  @Named("stringToEnum")
  default <T extends EnumMessage> T mapStringToEnum(
      final String message, @TargetType final Class<T> enumClass) {
    final T[] values = enumClass.getEnumConstants();
    return Arrays.stream(values)
        .filter(enumValue -> enumValue.carrier(message))
        .findFirst()
        .orElse(null);
  }

  @Named("enumToString")
  default <T extends EnumMessage> String mapEnumToString(final T enumValue) {
    return enumValue.getMessage();
  }
}

我无法通过考试。

 public class EnumMapperTest {
    
      @Test
      void checkMapping() {
        TargetX target = new TargetX();
        target.name = "MapStructTesting";
        target.messageA = EnumMessageA.GREAT;
        Assertions.assertEquals(
            "You are doing great".toUpperCase(), EnumMapper.INSTANCE.toSource(target).message);
    
        SourceX source = new SourceX();
        source.name = "MapStructTesting";
        source.message = "You are doing ok";
        Assertions.assertEquals(EnumMessageA.OK, EnumMapper.INSTANCE.toTarget(source).messageA);
      }
    }

我尝试使用或不使用qualifiedByName,但无法让 MapStruct 使用mapStringToEnum 方法。

我不确定这是否是 MapStruct 中的一个错误,在使用 @TargetType 时无法使用 Enum 继承,或者我遗漏了一些东西。

  • 使用@Mapping(source = "message", target = "messageA", qualifiedByName = "stringToEnum")时,编译时报错:
    error: Qualifier error. No method found annotated with @Named#value: [ stringToEnum ]. See https://mapstruct.org/faq/#qualifier for more info.
      @Mapping(source = "message", target = "messageA", qualifiedByName = "stringToEnum")
     error: Can't map property "String message" to "EnumMessageA messageA". Consider to declare/implement a mapping method: "EnumMessageA map(String value)".
      @Mapping(source = "message", target = "messageA", qualifiedByName = "stringToEnum")
  • 当使用@Mapping(source = "message", target = "messageA") 或resultType @Mapping(source = "message", target = "messageA", resultType = EnumMessage.class 时,生成的实现会忽略提供的方法。
class EnumMapperImpl implements EnumMapper {

    @Override
    public TargetX toTarget(SourceX source) {
        if ( source == null ) {
            return null;
        }

        TargetX targetX = new TargetX();

        if ( source.message != null ) {
            targetX.messageA = Enum.valueOf( EnumMessageA.class, source.message );
        }
        targetX.name = source.name;

        return targetX;
    }

    @Override
    public SourceX toSource(TargetX target) {
        if ( target == null ) {
            return null;
        }

        SourceX sourceX = new SourceX();

        sourceX.message = mapEnumToString( target.messageA );
        sourceX.name = target.name;

        return sourceX;
    }
}

如果有更优雅的方法来概括映射,我愿意接受建议。 注意:我不能使用@BeforeMapping / @AfterMapping,因为我有许多要映射的枚举类型,因此需要寻找隐式或通用的解决方案。

【问题讨论】:

    标签: java inheritance enums mapstruct targettype


    【解决方案1】:

    想通了,并在 GitHub 上向 MapStruct 团队提出了一个错误。

    要使其正常工作,必须满足以下条件:

    1. 映射器方法必须是static
    2. qualifiedByName 属性当然是必需的,即使我将通用签名更改为 &lt;T extends Enum&lt;T&gt; &amp; EnumMessage&gt;

    所以我修改后的代码是这样的:

    @Mapper
    public class EnumMapperHelper {
    
      @Named("stringToEnum")
      public static <T extends EnumMessage> T mapStringToEnum(
          final String message, @TargetType final Class<T> enumClass) {
        final T[] values = enumClass.getEnumConstants();
        return Arrays.stream(values)
            .filter(enumValue -> enumValue.carrier(message))
            .findFirst()
            .orElse(null);
      }
    
      @Named("enumToString")
      //this doesn't have to be static but yes the @Qualifier is required
      public static <T extends EnumMessage> String mapEnumToString(final T enumValue) {
        return enumValue.getMessage();
      }
    }
    
    
    @Mapper(uses = EnumMapperHelper.class) 
    interface EnumMapper {
      EnumMapper INSTANCE = Mappers.getMapper(EnumMapper.class);
    
      @Mapping(source = "message", target = "messageA", qualifiedByName = "stringToEnum")
      TargetX toTarget(SourceX source);
    
      @Mapping(source = "messageA", target = "message", qualifiedByName = "enumToString")
      SourceX toSource(TargetX target);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-01
      • 2018-07-08
      • 1970-01-01
      • 1970-01-01
      • 2020-04-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多