Why Upgrading Hutool Can Break Bean Copy and Safer Alternatives
Upgrading the Hutool library from 5.7.2 to 5.8.8 caused unexpected BeanUtil.copyProperties failures due to new validation logic, prompting a detailed analysis of the issue and a comparison of safer object‑mapping approaches such as explicit getters/setters, ModelMapper, and MapStruct.
Introduction
Our project needed to upgrade the
hutoollibrary to fix a security vulnerability, but the upgrade introduced a larger problem when using
BeanUtil.copyProperties()for DTO‑to‑entity conversion.
Event Review
We originally used
hutoolversion 5.7.2. The DTO and entity classes heavily relied on
BeanUtil.copyProperties(). Sample code:
<code>@Data
@ToString
public class DiagramDTO {
private String id;
private String code;
private String name;
}
</code> <code>@Data
@ToString
public class Diagram {
private Integer id;
private String code;
private String name;
}
</code> <code>public class BeanCopyTest {
public static void main(String[] args) {
DiagramDTO diagramDTO = new DiagramDTO();
diagramDTO.setId("3em3dgqsgmn0");
diagramDTO.setCode("d1");
diagramDTO.setName("图表");
Diagram diagram = new Diagram();
BeanUtil.copyProperties(diagramDTO, diagram);
System.out.println("数据实体对象:" + diagram);
diagram.setId(null);
}
}
</code>Before the upgrade,
hutool5.7.2 handled type differences gracefully, so the business logic worked.
After upgrading to
hutool5.8.8, the copy operation threw an exception because the new implementation adds validation that rejects IDs containing the character "e", causing unpredictable failures in production.
Analysis
Many developers prefer the convenience of
BeanUtil.copyProperties, but it can hide serious risks: type mismatches, silent field removals, and runtime errors that are only discovered in production.
For example, if a teammate silently removes or changes a field in the DTO, the copy method will not raise a compile‑time error, making the issue hard to trace.
Recommended Solutions
Prefer explicit
getand
setmethods so the compiler catches missing fields.
Using explicit getters/setters forces the compiler to alert you when a field is removed, preventing silent failures.
For larger objects, consider the following open‑source libraries:
ModelMapper – uses reflection to map objects automatically.
<code>private static void testModelMapper() {
ModelMapper modelMapper = new ModelMapper();
DiagramDTO diagramDTO = new DiagramDTO();
diagramDTO.setId("3em3dgqsgmn0");
diagramDTO.setCode("d1");
diagramDTO.setName("图表");
Diagram diagram = modelMapper.map(diagramDTO, Diagram.class);
}
</code>MapStruct – generates mapping code at compile time for better performance.
<code>@Mapper
public interface DiagramMapper {
DiagramMapper INSTANCE = Mappers.getMapper(DiagramMapper.class);
DiagramDTO toDTO(Diagram diagram);
Diagram toEntity(DiagramDTO diagram);
}
private static void testMapStruct() {
DiagramDTO diagramDTO = new DiagramDTO();
diagramDTO.setId("3em3dgqsgmn0");
diagramDTO.setCode("d1");
diagramDTO.setName("图表");
Diagram diagram = DiagramMapper.INSTANCE.toEntity(diagramDTO);
}
</code>MapStruct’s compile‑time generation avoids the runtime reflection overhead of ModelMapper.
Conclusion
Copying objects between layers with
BeanUtil.copyPropertiesis risky; using explicit getters/setters, ModelMapper, or MapStruct provides safer, more maintainable alternatives. While BeanUtil can still be useful for simple, internal conversions, critical data transformations should rely on compile‑time‑checked approaches.
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.