Why Not to Use Spring BeanUtils for Object Copying and How MapperStruct Improves Performance

Spring’s BeanUtils.copyProperties is error‑prone and slow due to type mismatches, primitive‑wrapper issues, null overwrites and reflection, whereas MapStruct generates compile‑time, type‑safe mapper code that avoids these pitfalls, delivers far better performance, and integrates easily with Maven and Lombok.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
Why Not to Use Spring BeanUtils for Object Copying and How MapperStruct Improves Performance

In Java business development, copying properties between BO, PO, DTO objects often uses Spring's BeanUtils.copyProperties, but it has several drawbacks.

Inconsistent property types cause copy failure : e.g., Long vs String leads to null values.

Primitive vs wrapper mismatch : Boolean fields with is -prefixed getters may fail.

Null values overwrite existing data : copying a DTO with null fields overwrites non‑null fields in the target.

Reflection‑based implementation is slow .

Incorrect imports can cause runtime errors .

Note: If a boolean property uses both primitive and wrapper types and its name starts with is , BeanUtils may fail to copy it.

MapperStruct addresses these issues. It generates type‑safe, pre‑compiled mapping code, eliminating reflection overhead and providing much higher performance than BeanUtils.

Example of generated mapper implementation (simplified):

@Generated(value = "org.mapstruct.ap.MappingProcessor", date = "2024-02-07T00:50:05+0800", comments = "version: 1.4.2.Final, compiler: javac, environment: Java 1.8.0_211 (Oracle Corporation)")
public class XXXDTOConverterImpl implements XXXDTOConverter {
    @Override
    public XXXBO convertDtoToBo(XXXDTO xxxDTO) {
        if (xxxDTO == null) {
            return null;
        }
        XXXBO xxxBO = new XXXBO();
        xxxBO.setId(xxxDTO.getId());
        xxxBO.setLabelName(xxxDTO.getLabelName());
        xxxBO.setSortNum(xxxDTO.getSortNum());
        xxxBO.setCategoryId(xxxDTO.getCategoryId());
        return xxxBO;
    }
}

To use MapperStruct, add Maven dependencies:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.4.2.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.4.2.Final</version>
</dependency>

Define DTO and BO classes, then create a mapper interface:

@Mapper
public interface SubjectLabelDTOConverter {
    SubjectLabelDTOConverter INSTANCE = Mappers.getMapper(SubjectLabelDTOConverter.class);
    SubjectLabelBO convertDtoToBo(SubjectLabelDTO subjectLabelDTO);
}

Usage example:

public Result<Boolean> add(SubjectLabelDTO subjectLabelDTO) {
    SubjectLabelBO subjectLabelBO = SubjectLabelDTOConverter.INSTANCE.convertDtoToBo(subjectLabelDTO);
    // ...
}

Note: MapperStruct also performs shallow copy; deep copy requires additional converters. When used together with Lombok, ensure Lombok dependency is declared after MapStruct to avoid null‑value issues.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaReflectionBeanUtilsmapstructObject Mapping
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.