Java Can';t让MapStruct使用枚举继承&@塔格提普

Java Can';t让MapStruct使用枚举继承&@塔格提普,java,inheritance,enums,mapstruct,targettype,Java,Inheritance,Enums,Mapstruct,Targettype,以下是我的示例设置: interface EnumMessage { boolean carrier(String message); String getValue(); default String getMessage() { return getValue().toUpperCase(); } } enum EnumMessageA implements EnumMessage { GREAT("You are doing great"

以下是我的示例设置:

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();
  }
}
我尝试使用或不使用
qualifiedByName
,但无法让MapStruct使用
mapStringToEnum
方法

我不确定这是否是MapStruct在使用
@TargetType
时不使用枚举继承的错误,或者我遗漏了什么

  • 使用
    @映射(source=“message”,target=“messageA”,qualifiedByName=“stringToEnum”)
    时,会出现编译时错误:
  • 使用
    @Mapping(source=“message”,target=“messageA”)
    或使用resultType
    @Mapping(source=“message”,target=“messageA”,resultType=EnumMessage.class
    时,生成的实现会忽略提供的方法
如果有更优雅的方法来概括映射,我愿意接受建议。
注意:我不能使用
@BeforeMapping/@AfterMapping
,因为我有许多要映射的枚举类型,因此需要寻找隐式或通用的解决方案。

解决了这个问题,并且在MapStruct团队的帮助下引发了一个错误

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

  • 映射器方法必须是静态的
  • qualifiedByName
    属性当然是必需的,即使我将通用签名更改为
  • 因此,我修改的代码如下所示:

    @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);
    }
    
    @Mapper
    公共类EnumMapperHelper{
    @命名(“stringToEnum”)
    公共静态T mapStringToEnum(
    最终字符串消息,@TargetType最终类enumClass){
    最终T[]值=enumClass.getEnumConstants();
    返回Arrays.stream(值)
    .filter(enumValue->enumValue.carrier(消息))
    .findFirst()
    .orElse(空);
    }
    @命名(“枚举字符串”)
    //这不必是静态的,但需要@Qualifier
    公共静态字符串mapEnumToString(最终Enumt值){
    返回enumValue.getMessage();
    }
    }
    @映射器(uses=EnumMapperHelper.class)
    接口枚举映射器{
    EnumMapper实例=Mappers.getMapper(EnumMapper.class);
    @映射(source=“message”、target=“messageA”、qualifiedByName=“stringToEnum”)
    TargetX toTarget(源X源);
    @映射(source=“messageA”,target=“message”,qualifiedByName=“enumToString”)
    SourceX-toSource(TargetX-target);
    }
    
        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")
    
    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;
        }
    }
    
    @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);
    }