Best Practices for Java Bean Conversion, Validation, and Refactoring
This article discusses practical techniques for Java developers, covering bean conversion using DTOs and Spring utilities, validation with JSR‑303, leveraging Lombok for cleaner code, applying design patterns, and systematic refactoring to improve readability, maintainability, and overall code quality in backend projects.
The article begins by stating that it is not a bragging piece but a practical guide focusing on fundamental issues and coding practices for Java developers, especially when working with Spring Boot, MyBatis Plus, and Vue.
It references a full‑stack admin system project (https://github.com/YunaiV/ruoyi-vue-pro) that supports RBAC, multi‑tenant, workflow, third‑party login, payment, SMS, and e‑commerce features.
IDE Recommendation : The author advises switching from Eclipse to IntelliJ IDEA for better performance and productivity, emphasizing that the choice of IDE is not the main focus of the article.
Bean Conversion and DTO Usage : The article explains why domain packages should be named entity instead of domain and introduces DTOs for data transfer. It shows a simple controller method that manually copies properties:
@RequestMapping("/v1/api/user")
@RestController
public class UserApi {
@Autowired
private UserService userService;
@PostMapping
public User addUser(UserInputDTO userInputDTO) {
User user = new User();
user.setUsername(userInputDTO.getUsername());
user.setAge(userInputDTO.getAge());
return userService.addUser(user);
}
}To avoid repetitive setters, the author recommends using BeanUtils.copyProperties :
@PostMapping
public User addUser(UserInputDTO userInputDTO) {
User user = new User();
BeanUtils.copyProperties(userInputDTO, user);
return userService.addUser(user);
}For better semantics, the conversion is extracted into a method:
private User convertFor(UserInputDTO dto) {
User user = new User();
BeanUtils.copyProperties(dto, user);
return user;
}The article then introduces a generic DTOConvert<S,T> interface and its implementation, showing how to encapsulate conversion logic and improve readability.
public interface DTOConvert
{
T convert(S s);
}
public class UserInputDTOConvert implements DTOConvert
{
@Override
public User convert(UserInputDTO dto) {
User user = new User();
BeanUtils.copyProperties(dto, user);
return user;
}
}It also demonstrates using Guava's Converter to provide forward and backward conversion, with an example that throws an AssertionError for unsupported reverse conversion.
private static class UserInputDTOConvert extends Converter
{
@Override
protected User doForward(UserInputDTO dto) {
User user = new User();
BeanUtils.copyProperties(dto, user);
return user;
}
@Override
protected UserInputDTO doBackward(User user) {
throw new AssertionError("Reverse conversion not supported!");
}
}Bean Validation (JSR‑303) : The author stresses the importance of server‑side validation using annotations like @NotNull and the @Valid parameter in Spring MVC, followed by handling BindingResult to return meaningful API errors.
public class UserDTO {
@NotNull
private String username;
@NotNull
private int age;
}
@PostMapping
public UserDTO addUser(@Valid UserDTO userDTO, BindingResult result) {
if (result.hasErrors()) {
// throw custom validation exception
}
// conversion and service call
}Embracing Lombok : To reduce boilerplate, the article shows Lombok annotations ( @Getter , @Setter , @Data , @AllArgsConstructor , @NoArgsConstructor , @Accessors(chain = true) ) and how they simplify beans, builders, and static factory methods.
@Accessors(chain = true)
@Getter
@Setter
@RequiredArgsConstructor(staticName = "of")
public class Student {
@NonNull private String name;
private int age;
}
Student s = Student.of("zs").setAge(24);It also covers Lombok's @Builder for fluent object creation:
@Builder
public class Student {
private String name;
private int age;
}
Student s = Student.builder().name("zs").age(24).build();Design Patterns and Refactoring : The author advises using appropriate patterns (e.g., Strategy instead of over‑engineered State) and emphasizes systematic refactoring. An example of time‑based order distribution logic using Joda‑Time is provided, showing clean separation of concerns.
private static final DateTime SPLIT_TIME = new DateTime().withTime(15,0,0,0);
private Date calculateDistribution(Date orderTime) {
DateTime dt = new DateTime(orderTime);
Date nextDay = dt.plusDays(1).toDate();
Date dayAfter = dt.plusDays(2).toDate();
return dt.isAfter(SPLIT_TIME) ? wrap(dayAfter) : wrap(nextDay);
}
private Date wrap(Date d) {
DateTime dt = new DateTime(d);
return dt.getDayOfWeek() == DateTimeConstants.SUNDAY ? dt.plusDays(1).toDate() : d;
}Additional topics include proxying RestTemplate with @Delegate to reduce boilerplate, the importance of clean code, UML basics, and Linux command familiarity for Java developers.
Overall, the article provides a comprehensive guide to writing cleaner, more maintainable Java backend code by leveraging DTO conversion, validation, Lombok, design patterns, and disciplined refactoring.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
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.