Как заполнить карту внутри целевого объекта, скопировав значения из исходного объекта с помощью -MapStruct?
Я новичок в Mapstruct. У меня есть сценарий, в котором в моем целевом объекте у меня есть карта Java с парой значений ключа
Мой код выглядит примерно так (фиктивный код):
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)
Любая помощь, любое предложение или обходной путь приветствуются. Заранее спасибо.
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);
}
}
Как насчет этого:
@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>
но идея та же..
Я бы написал метод 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);
}