Master Java Object Mapping: VO, BO, DTO, PO with Simple Object Copy
This article explains the different POJO variants—VO, BO, PO, DTO, and DO—describes their typical usage in layered Java applications, introduces the Simple Object Copy IntelliJ plugin for one‑click conversion method generation, compares it with common mapping tools such as MapStruct and BeanUtils, and discusses performance and flexibility advantages.
In Java projects a POJO (Plain Old Java Object) can be classified into several roles:
VO (View Object) : objects returned to the front‑end for display.
BO (Business Object) : objects used inside the service layer to encapsulate business logic.
PO (Persistent Object) : objects that directly map to database tables and hold persisted data.
DTO (Data Transfer Object) : objects transferred between services or layers to decouple components.
DO (Domain Object) : in Alibaba's manual it is equivalent to PO, while in Domain‑Driven Design it corresponds to BO.
Typical conversion flow: DTO → BO (service layer) → VO (controller layer) → front‑end. The following reference documents provide more details:
https://juejin.cn/post/6952848675924082718
https://juejin.cn/post/6844904046097072141
https://zhuanlan.zhihu.com/p/264675395Simple Object Copy Plugin
The IntelliJ IDEA plugin Simple Object Copy generates conversion methods between objects with a single shortcut (Alt+Insert on Windows or ⌘+N on macOS). No manual code is required for simple field copying.
Example of a generated conversion method for UserVO:
@Data
public class UserVO {
private String name;
private Date entryDate;
private String userId;
private List<RoleVO> roleList;
private RoomVO room;
public static UserVO convertToUserVO(UserDTO item) {
if (item == null) {
return null;
}
UserVO result = new UserVO();
result.setName(item.getName());
result.setEntryDate(item.getEntryDate());
result.setUserId(item.getUserId());
List<RoleDTO> roleList = item.getRoleList();
if (roleList == null) {
result.setRoleList(null);
} else {
result.setRoleList(roleList.stream().map(UserVO::convertToRoleVO).collect(Collectors.toList()));
}
result.setRoom(convertToRoomVO(item.getRoom()));
return result;
}
}Generated code screenshots:
Comparison with Other Mapping Tools
Common Java mapping utilities include:
Spring BeanUtils (copyProperties)
Cglib BeanCopier (copyProperties)
Apache BeanUtils (copyProperties)
Apache PropertyUtils (copyProperties)
Dozer
MapStruct
JSON serialization + deserialization
These tools require adding external dependencies and invoking specific APIs. They often rely on reflection or proxies, which can cause performance overhead and make the code harder to read. Missing or renamed fields usually require additional manual mapping code.
MapStruct Example
@Mapper(componentModel = "spring", uses = {RoleVOMapper.class, RoomVOMapper.class})
public interface UserMapper {
UserVO toUserVO(UserDTO userDTO);
}
@Mapper(componentModel = "spring")
public interface RoleMapper {
RoleVO toRoleVO(RoleDTO roleDTO);
}
@Mapper(componentModel = "spring")
public interface RoomMapper {
RoomVO toRoomVO(RoomDTO roomDTO);
}When the source DTO lacks fields such as roomName or buildingName, MapStruct requires extra mapping methods, and the compiler will not warn about the missing fields.
BeanUtils Example
@Data
public class UserVO {
// fields omitted for brevity
public static UserVO convertToUserVO(UserDTO item) {
if (item == null) {
return null;
}
UserVO result = new UserVO();
BeanUtils.copyProperties(item, result);
// manual handling of nested objects and missing fields
List<RoleDTO> roleList = item.getRoleList();
if (roleList == null) {
result.setRoleList(null);
} else {
result.setRoleList(roleList.stream().map(UserVO::convertToRoleVO).collect(Collectors.toList()));
}
result.setRoom(convertToRoomVO(item.getRoom()));
return result;
}
}BeanUtils uses reflection, which leads to slower performance and does not generate compile‑time checks for missing fields.
Performance and Flexibility
Simple Object Copy generates plain setter calls, avoiding reflection and proxy generation, resulting in a performance advantage that is an order of magnitude better than the reflective approaches. It also creates empty methods for fields that do not exist in the source object, prompting developers to fill them and preventing silent null values.
Other Useful Plugins
Another handy plugin is generateAllSetter , which can be used together with Simple Object Copy to generate all setter methods automatically.
Installation
Open IntelliJ IDEA, go to the Plugins marketplace, search for “Simple Object Copy”, and install it.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
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.
