Master Object Mapping in Java with MapStruct: PO ↔ VO, Lists, and Merges
Learn how to efficiently convert between PO, VO, and DTO objects in Java using Spring BeanUtils for identical fields and MapStruct for custom mappings, including single objects, lists, and merging multiple sources, with full Maven setup and generated implementation details.
In work we often need to convert between different objects.
PO (persistent object) corresponds to a database record, VO (view object) is returned to the front‑end, DTO (data transfer object) is used for service communication.
If the property names are identical you can use Spring BeanUtils or Cglib BeanCopier (avoid Apache BeanUtils due to poor performance).
When property names differ or you need to merge multiple PO objects into a VO, MapStruct is a powerful tool.
Add the following dependencies to your pom:
<code><dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.CR1</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.CR1</version>
<scope>provided</scope>
</dependency></code>Object conversion
<code>@Data
@Builder
public class StudentPO {
private Integer id;
private String name;
private Integer age;
private String className;
}</code> <code>@Data
public class StudentVO {
private Integer id;
private String studentName;
private Integer studentAge;
private String schoolName;
}</code> <code>@Mapper
public interface StudentMapper {
StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);
@Mappings({
@Mapping(source = "name", target = "studentName"),
@Mapping(source = "age", target = "studentAge")
})
StudentVO po2Vo(StudentPO studentPO);
}
</code>Create a mapper interface and annotate it with @Mapper.
Add a static INSTANCE field.
Use @Mapping to define field mappings; identical names are mapped automatically.
Test shows that fields without explicit mapping are set to null.
<code>@Test
public void studentPo2Vo() {
StudentPO studentPO = StudentPO.builder()
.id(10).name("test").age(24).className("教室名").build();
StudentVO studentVO = StudentMapper.INSTANCE.po2Vo(studentPO);
// StudentVO(id=10, studentName=test, studentAge=24, schoolName=null)
System.out.println(studentVO);
}
</code>List conversion
<code>@Mapper
public interface StudentMapper {
// previous method ...
List<StudentVO> poList2VoList(List<StudentPO> studentPO);
}
</code>MapStruct reuses the single‑object mapping rules for list conversion.
<code>@Test
public void poList2VoList() {
List<StudentPO> studentPOList = new ArrayList<>();
for (int i = 1; i <= 2; i++) {
StudentPO studentPO = StudentPO.builder()
.id(i).name(String.valueOf(i)).age(i).build();
studentPOList.add(studentPO);
}
List<StudentVO> studentVOList = StudentMapper.INSTANCE.poList2VoList(studentPOList);
// [StudentVO(id=1, studentName=1, studentAge=1, schoolName=null),
// StudentVO(id=2, studentName=2, studentAge=2, schoolName=null)]
System.out.println(studentVOList);
}
</code>Merging multiple objects into one
<code>@Data @Builder public class SchoolPO { private String name; private String location; }
@Data @Builder public class StudentPO { private Integer id; private String name; private Integer age; private String className; }
@Data public class SchoolStudentVO { private String schoolName; private String studentName; }
</code> <code>@Mapper
public interface StudentMapper {
@Mappings({
@Mapping(source = "schoolPO.name", target = "schoolName"),
@Mapping(source = "studentPO.name", target = "studentName")
})
SchoolStudentVO mergeVo(SchoolPO schoolPO, StudentPO studentPO);
}
</code> <code>@Test
public void mergeVo() {
SchoolPO schoolPO = SchoolPO.builder().name("学校名字").build();
StudentPO studentPO = StudentPO.builder().name("学生名字").build();
SchoolStudentVO schoolStudentVO = StudentMapper.INSTANCE.mergeVo(schoolPO, studentPO);
// SchoolStudentVO(schoolName=学校名字, studentName=学生名字)
System.out.println(schoolStudentVO);
}
</code>MapStruct generates an implementation class at compile time, for example:
<code>public class StudentMapperImpl implements StudentMapper {
// generated methods po2Vo, poList2VoList, mergeVo ...
}
</code>macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.