3

I Have a problem attempting mapping to an ENUM from an Integer value, my method mapping its:

@Mapping(
      target = "myModel.states",// this is my ENUM
      source = "source.stateId") // this is the Integer Value
  ClsTargetModel mapCreditCard(ClsMyClass source);

ENUM and entity model:

Entity:

@Getter
@Setter
@Entity
@Table(name = "my_table")
public class MyEntityModel {
  @Id
  @Column(name = "id")
  private Integer id;

  @Basic
  @Column(name = "description")
  private String description;
}

ENUM:

@Getter
@ToString
public enum EnumStates {
  STATE1(1),
  STATE2(2),
  STATE3(3);

  public Integer id;

  EnumStates(Integer id) {
    this.id = id;
  }

  public static EnumStates getStateById(Integer stateId) {
    return Arrays.stream(EnumStates.values())
        .filter(enumStateValue -> enumStateValue.id == stateId)
        .findFirst()
        .orElse(null);
  }
}

When Im trying of mapping the ID from Model Entity to the ENUM, then mapstruct show me an error:

error: Can't map property "java.lang.Integer Id" to "EnumStates states". Consider to declare/implement a mapping method: "EnumStates map(java.lang.Integer value)".

I think that the method was declare in the enum, but mapstruct always responds that error, can you check my code please ?

EdwinCab
  • 361
  • 1
  • 3
  • 17
  • This works for me .. Not using Getter or ToString annotations. Copied to Java Playground.. https://i.stack.imgur.com/8yHR2.png So it must be something in the annotations I presume. – JGFMK Jul 14 '20 at 16:56
  • Thanks @JGFMK, its very strange, I cannot see the error in the logic using mapstruct. – EdwinCab Jul 14 '20 at 17:01
  • https://github.com/mapstruct/mapstruct/issues/749 - seems to be an issue covered here. But not sure where they got with it. – JGFMK Jul 14 '20 at 21:05
  • Duplicate of https://stackoverflow.com/questions/43356232/how-can-i-map-an-enum-to-a-boolean-with-mapstruct and https://stackoverflow.com/questions/48570827/from-string-to-enum-using-mapstruct – Roman Sinyakov May 17 '22 at 08:21

1 Answers1

7

You need to tell mapstruct how to map from an integer value to your enum.

A possible solution could be:

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper
public interface ClsMapper {

    @Mapping(
            target = "states",// this is my ENUM
            source = "id") //
    ClsTargetModel to(ClsMyClass clsMyClass);

    default EnumStates map(int value) {
        return EnumStates.getStateById(value);
    }
}

Check that I have created a map method where I tell mapstruct how to convert an int to a EnumStates. Using the conversion method you created inside the enum.

I have simplified the model classes as I am not using lombok nor database for this example. It is pretty much same code as yours I didn't change any logic.

public class ClsMyClass {
    private int id;
    private String description;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
public class ClsTargetModel {
    private EnumStates states;

    public EnumStates getStates() {
        return states;
    }

    public void setStates(EnumStates states) {
        this.states = states;
    }
}
public enum EnumStates {
    STATE1(1),
    STATE2(2),
    STATE3(3);

    public Integer id;

    EnumStates(Integer id) {
        this.id = id;
    }

    public static EnumStates getStateById(Integer stateId) {
        return Arrays.stream(EnumStates.values())
                .filter(enumStateValue -> enumStateValue.id == stateId)
                .findFirst()
                .orElse(null);
    }
}

Then mapstruct autogenerate a mapper code like:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2020-07-26T14:31:58+0200",
    comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_144 (Oracle Corporation)"
)
public class ClsMapperImpl implements ClsMapper {

    @Override
    public ClsTargetModel to(ClsMyClass clsMyClass) {
        if ( clsMyClass == null ) {
            return null;
        }

        ClsTargetModel clsTargetModel = new ClsTargetModel();

        clsTargetModel.setStates( map( clsMyClass.getId() ) );

        return clsTargetModel;
    }
}

I hope this solves your issue, let me know in case of any doubt.

Pablo AM
  • 294
  • 1
  • 10