Chuyển đổi dữ liệu (MapStruct)
govex-cloud-mapstruct là thư viện annotation + runtime conversion cho các mapper MapStruct sinh tự động: khai báo mapper bằng @AutoMapper, @AutoMapMapper, @AutoEnumMapper và gọi chuyển đổi qua bean GConversionService. Thêm dependency khi service cần chuyển đổi entity ↔ DTO/VO mà không muốn viết tay mapper.
Khi nào sử dụng
- Cần chuyển entity ↔ DTO/VO, kể cả
List, mà không viết mapper thủ công. - Cần chuyển
Mapsang object (ví dụ map cấu hình động thành class cấu hình). - Cần chuyển đổi enum sang giá trị code và ngược lại.
- Cần tránh đệ quy vô hạn khi map quan hệ vòng (entity cha ↔ con).
- Cần một điểm gọi chuyển đổi thống nhất trong mã nghiệp vụ (
GConversionService).
Cài đặt
Thêm dependency (không khai version — version do BOM quản lý, xem Cài đặt):
<dependency>
<groupId>vn.govex.cloud</groupId>
<artifactId>govex-cloud-mapstruct</artifactId>
</dependency>
Annotation của dependency có RetentionPolicy.SOURCE và chỉ được xử lý tại compile-time: bắt buộc khai báo govex-cloud-mapstruct-processor trong annotationProcessorPaths thì mapper mới được sinh — xem govex-cloud-mapstruct-processor.
Cấu hình
Auto-configuration tạo sẵn hai bean và có thể thay thế bằng bean riêng:
| Bean | Kiểu | Điều kiện | Mô tả |
|---|---|---|---|
converterFactory | ConverterFactory | @ConditionalOnMissingBean | Mặc định SpringConverterFactory tra mapper trong ApplicationContext |
converter | GConversionService | @ConditionalOnMissingBean | Facade chuyển đổi dùng trong mã nghiệp vụ |
Có thể thay ConverterFactory bằng cơ chế tra cứu khác (ví dụ DefaultConverterFactory quét classpath qua Mappers của MapStruct).
Sử dụng
Khai báo mapper trên lớp nguồn
@AutoMapper(target = UserVO.class)
@Data
public class User {
private String name;
private Integer age;
}
Processor sinh interface UserToUserVOMapper (tên mặc định {Nguồn}To{Đích}Mapper) — có thể đổi bằng mapperName/mapperNameSuffix.
Gọi chuyển đổi qua bean converter
@RequiredArgsConstructor
@Service
public class UserService {
private final GConversionService converter;
public UserVO toVo(User user) {
return converter.convert(user, UserVO.class);
}
public List<UserVO> toVoList(List<User> users) {
return converter.convert(users, UserVO.class);
}
public UserVO update(User source, UserVO target) {
return converter.convert(source, target);
}
}
Map sang object và enum
@AutoMapMapper
public class Setting {
private String key;
private String value;
}
// Map<String, Object> map = ...;
Setting setting = converter.convert(map, Setting.class);
@AutoEnumMapper("code")
public enum Status {
ACTIVE(1), INACTIVE(0);
// getter cho field code...
}
Tránh đệ quy khi map quan hệ vòng
@AutoMapper(target = NodeVO.class, cycleAvoiding = true)
public class Node {
private Node parent;
private List<Node> children;
}
NodeVO vo = converter.convert(node, NodeVO.class, new CycleAvoidingMappingContext());
Cấu hình tập trung cho mapper
@AutoMapperConfig(mapperPackage = "vn.govex.app.mapper")
public class MapperConfig { }
Mỗi module biên dịch chỉ được có một class gắn @AutoMapperConfig; các policy mặc định (unmapped source/target, null handling...) khai báo tại đây áp dụng cho toàn bộ mapper trong module.
Lưu ý
- Bắt buộc có
govex-cloud-mapstruct-processortrên annotation processor path; nếu không, annotation bị bỏ qua và không có mapper nào được sinh. - Mapper mặc định sinh trong package của lớp nguồn; đổi qua
mapperPackageở@AutoMapperConfighoặc compiler option. - Adapter
@Component(MapperConverterAdapter,MapMapperConverterAdapter) mặc định nằm trong packagevn.govex.cloud.mapstruct— package này được auto-configuration component-scan. ĐổiadapterPackage/autoConfigPackagephải đảm bảo package đó cũng được scan. GConversionService.convertnémConvertExceptionkhi không tìm thấy mapper phù hợp; kiểm tra lại cặp kiểu nguồn/đích khi gặp lỗi này.- Khi dùng chung với Lombok, thêm
lombok-mapstruct-bindingvàoannotationProcessorPathsđể hai processor phối hợp đúng thứ tự.