Mastering BO, DTO, VO, PO: When and How to Use Java Object Mapping Tools
This article clarifies the purpose of Java classes ending with “O”—BO, DTO, VO, PO—explains their proper usage in a typical front‑end/back‑end workflow, and compares mapping solutions like Spring BeanUtils and MapStruct with code examples.
In modern front‑end/back‑end separated projects, Java classes whose names end with “O” (BO, DTO, VO, PO) serve distinct purposes. This article explains what each represents, when to use them, and how to map between them efficiently.
1. Distinguishing BO, DTO, VO, PO
Typical request handling flow:
The front end sends request parameters encapsulated in a DTO object.
If the business logic is simple, the controller can work directly with the DTO; for complex logic, a BO (Business Object) is created to hold business data.
Database entities are represented by PO (or DO) classes, to which the BO/DTO is mapped before persisting.
After processing, the data returned to the front end is wrapped in a VO (View Object).
2. Object‑mapping tools
2.1 Spring BeanUtils
Spring provides BeanUtils.copyProperties(dest, src) to copy matching properties between beans, reducing manual setter code. Variants allow ignoring specific properties or limiting to properties defined in the target class.
2.2 MapStruct
When property names or types differ, MapStruct generates type‑safe mappers at compile time.
Dependency configuration (Maven):
<code><dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency></code>Basic mapper interface:
<code>@Mapper
public interface UserConvertBasic {
// Convert entity to VO
UserVO toConvertVO1(User source);
// Convert VO back to entity
User fromConvertEntity1(UserVO1 userVO1);
}</code>Using Spring component model:
<code>@Mapper(componentModel = "spring")
public interface UserConvertBasic {
UserVO toConvertVO1(User source);
User fromConvertEntity1(UserVO1 userVO1);
}</code>When source and target property names differ, explicit mappings are required:
<code>@Mapper(componentModel = "spring")
public interface UserConvertBasic {
@Mappings({
@Mapping(source = "id", target = "userId"),
@Mapping(source = "name", target = "userName")
})
UserV04 toConvertVo(User source);
}</code>MapStruct is powerful and supports many advanced features; other mapping libraries such as Dozer and Orika are also available.
Lobster Programming
Sharing insights on technical analysis and exchange, making life better through technology.
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.