Как заполнить карту внутри целевого объекта, скопировав значения из исходного объекта с помощью -MapStruct?

Я новичок в Mapstruct. У меня есть сценарий, в котором в моем целевом объекте у меня есть java-карта с парой ключевых значений ‹String, String›, и я должен заполнить эту карту, используя свойства внутренних объектов исходных объектов / значения элементов данных.

Мой код выглядит примерно так (фиктивный код):

public class Student {
    public String name;
    public String rollNo;
    public Map<String, String> marks;
}


public class ExamResult{

    public String stud_name;
    public String Stud_rollNo;
    public Marks marks;
}

public class Marks{
    public Integer English;
    public Integer Maths;
    public Integer Science;
}

Как мне вручную добиться того же, что показано ниже:

Student target;
ExamResult source;
target.setName(source.stud_name);
target.setRollNo(source.Stud_RollNo);
target.marks.put("ENGLISH",source.marks.english_marks);
target.marks.put("MATHS",source.marks.math_marks);
target.marks.put("SCIENCE",source.marks.science_marks);

Для прямого сопоставления свойств я нашел код, но не знаю, как сопоставить значения, которые нужно заполнить на карте marks.

Я подумал использовать выражение java для заполнения значений целевой карты, но не нашел никакой документации или такого примера выражений, используемых для целевого объекта.

Я думал использовать как показано ниже, но не уверен, что это сработает:

    @Mapping(source = "stud_name", target = "name")
    @Mapping(source = "Stud_RollNo", target = "rollNo")
    @Mapping(source = "source.marks.english_marks",target = "java( marks.put(\"ENGLISH\",source.marks.english_marks )")
    @Mapping(source = "source.marks.math_marks",target = "java( marks.put(\"MATHS\",source.marks.math_marks )")
    @Mapping(source = "source.marks.science_marks",target = "java( marks.put(\"SCIENCE\",source.marks.science_marks )")
Student doConvert(ExamResult src)

Любая помощь, любое предложение или обходной путь приветствуются. Заранее спасибо.


person Anonymous    schedule 17.07.2020    source источник


Ответы (3)


Использование выражений в target для MapStruct запрещено, поэтому вы не могли заставить его работать.

Сопоставление с картами из объектов также пока не поддерживается, у нас есть разные проблемы с запросом этой функции.

Я бы посоветовал как можно чаще использовать автоматическое сопоставление, когда это возможно, а затем прибегать к @AfterMapping, когда MapStruct не может этого сделать. Так что в вашем случае что-то вроде:

@Mapper
public interface StudentMapper {

    @Mapping(source = "stud_name", target = "name")
    @Mapping(source = "Stud_RollNo", target = "rollNo")
    @Mapping(target = "marks", ignore = true) // mapped in @AfterMapping
    Student doConvert(ExamResult src)

    @AfterMapping
    default void addStudentMarks(ExamResult result, @MappingTarget Student student) {
        student.marks = new HashMap<>();
        student.marks.put("ENGLISH", result.marks.ENGLISH);
        student.marks.put("MATHS", result.marks.MATHS);
        student.marks.put("SCIENCE", result.marks.SCIENCE);
    }

}
person Filip    schedule 23.07.2020

Я бы написал метод Custom mapper для преобразования меток в объект карты.

@Mapping(source = "stud_name", target = "name")
@Mapping(source = "Stud_rollNo", target = "rollNo")
Student doConvert(ExamResult examResult);

static Map<String,String> mapMarks(Marks marks) {
    Map<String,String> marksMap = new HashMap<>();
    marksMap.put("ENGLISH", String.valueOf(marks.getEnglish()));
    marksMap.put("MATHS", String.valueOf(marks.getMaths()));
    return marksMap;
}

В случае, если элементы карты слишком велики, чтобы их можно было упомянуть, можно использовать библиотеку Джексона, которая может динамически создавать карту с именем ссылки в качестве ключа и значением объекта в качестве значения.

@Mapping(source = "stud_name", target = "name")
@Mapping(source = "Stud_rollNo", target = "rollNo")
Student doConvert(ExamResult examResult);

ObjectMapper mapper = new ObjectMapper();
static Map<String,String> mapMarks(Marks marks) {
    return mapper.convertValue(marks, Map.class);
}
person SKumar    schedule 18.07.2020

как насчет этого:


@Mapper
public interface MyMapper {

    @Mapping( target = "name", source = "stud_name")
    @Mapping( target = "rollNo", source = "stud_rollNo")
    // marks will be mapped based on name equality
    Student map( ExamResult result);

    // mapstruct sees an unmapped property (although it only has a getter), marks
    @Mapping( target = "marks", ignore = true )
    MarksWrapper toWrapper(Marks marks );

    // handwritten method, just to do the mapping
    default Map<String, Integer> toMap( MarksWrapper wrapper) {
        return wrapper.getMarks();
    }

    // this class does the conversion
    class MarksWrapper {

        private Map<String, Integer> marks = new HashMap<>(  );

        public void setEnglish( Integer mark) {
            marks.put( "ENGLISH", mark );
        }
        public void setMaths( Integer mark ){
            marks.put( "MATH", mark );
        }
        public void setScience( Integer mark ) {
            marks.put( "SCIENCE", mark );
        }
        public Map<String, Integer> getMarks() {
            return marks;
        }
    }
}

Примечание: я использовал Map<String,Integer> Map<String,String>, но идея та же ...

person Sjaak    schedule 24.07.2020