Backend Development 10 min read

Using MapStruct for Efficient Bean Copying in Java Applications

This article explains why manual property copying in layered Java applications is inefficient, compares traditional approaches such as manual setters, Spring BeanUtils, and CGLIB BeanCopier, and demonstrates how MapStruct provides high‑performance, type‑safe, compile‑time generated mappers with support for deep copy, collection mapping, field ignoring, and Lombok integration.

Architecture Digest
Architecture Digest
Architecture Digest
Using MapStruct for Efficient Bean Copying in Java Applications

In multi‑layered Java projects, developers often need to copy data between objects like User and UserVO . The naive approach of writing a setter for each field is error‑prone and slow, while tools like IDE plugins only reduce typing effort without improving runtime performance.

Common runtime solutions include Apache BeanUtils (reflection‑based and discouraged by Alibaba Java guidelines), Spring BeanUtils (optimized but still reflective), and CGLIB BeanCopier (generates a subclass at first use, offering near‑native speed). These methods can cause hidden bugs, such as type mismatches (e.g., int to long ) or accidental copying of primary‑key fields.

MapStruct is a compile‑time annotation processor that generates type‑safe, high‑performance mappers. Its advantages are:

Performance: generated code uses plain setter calls, matching hand‑written speed.

Type safety: mismatched types cause compilation errors.

Rich features: deep copy, collection mapping, custom field mappings, and ignoring fields.

Simple usage: define a mapper interface and let MapStruct create the implementation.

Example mapper:

@Mapper
public interface BeanMapper {
    BeanMapper INSTANCE = Mappers.getMapper(BeanMapper.class);
    TargetData map(SourceData source);
}

Typical usage:

SourceData source = new SourceData();
source.setId("123");
source.setName("abc");
source.setCreateTime(System.currentTimeMillis());
TargetData target = BeanMapper.INSTANCE.map(source);
System.out.println(target.getId() + ":" + target.getName() + ":" + target.getCreateTime());

MapStruct defaults to shallow copy; to enable deep copy, annotate the method with @Mapping(target = "data", mappingControl = DeepClone.class) . Collection mapping is as easy as adding a method like List<TestData> map(List<TestData> source); .

When field types differ, MapStruct can either perform implicit conversion or, if configured with typeConversionPolicy = ReportingPolicy.ERROR , raise a compile‑time error, forcing the developer to define explicit mapping methods.

Fields that should never be copied (e.g., id , createTime , updateTime ) can be ignored via @Mapping(target = "id", ignore = true) or by creating a reusable annotation such as @IgnoreFixedField and applying it to the mapper method.

For projects using Lombok, include Lombok as an annotation processor in the Maven annotationProcessorPaths configuration so that generated mapper code compiles correctly.

MapStruct works by leveraging Java's annotation‑processing (JSR‑269) during compilation, similar to Lombok. The processor analyses source code, generates mapper implementations, and writes them to the target directory, avoiding runtime reflection overhead.

Overall, MapStruct offers a clean, compile‑time solution for bean copying, improving performance and maintainability compared to reflective utilities.

JavaPerformanceMapStructCodeGenerationDeepCopyBeanMapping
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login 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.