Introduction
MapStruct generates Java bean mapping code at compile time using annotation processing. Instead of writing tedious getter/setter boilerplate or relying on reflection at runtime, you define a mapper interface and MapStruct generates the implementation with plain method calls—fast, type-safe, and debuggable.
What MapStruct Does
- Generates mapping implementations from annotated Java or Kotlin interfaces
- Maps between beans with matching or explicitly mapped property names
- Handles nested objects, collections, enums, and type conversions automatically
- Integrates with dependency injection frameworks (Spring, CDI, JSR 330)
- Reports unmapped properties as compilation errors to prevent silent data loss
Architecture Overview
MapStruct hooks into the Java compiler as an annotation processor (JSR 269). When the compiler encounters a @Mapper interface, MapStruct's processor analyzes source and target types, resolves property mappings, and writes a concrete implementation class. The generated code is plain Java with direct method calls—no reflection, no proxies—so it runs at the same speed as hand-written mapping code.
Installation & Configuration
- Add
mapstructas a compile dependency andmapstruct-processoras an annotation processor - Works with Maven, Gradle, and any IDE supporting annotation processing
- Configure
componentModel = "spring"to generate Spring-injectable mappers - Use
@MappingTargetfor update-in-place patterns instead of creating new objects - Enable
unmappedTargetPolicy = ReportingPolicy.ERRORto fail on unmapped fields
Key Features
- Zero runtime overhead: generated code is plain getter/setter calls
- Compile-time error reporting for missing or ambiguous mappings
- Built-in type conversions between primitives, strings, dates, and enums
- Expression and qualifier annotations for custom conversion logic
- Support for mapping inheritance and shared configurations via
@MapperConfig
Comparison with Similar Tools
- ModelMapper — reflection-based runtime mapping; MapStruct is faster and catches errors at compile time
- Dozer — XML-configured bean mapper; MapStruct uses annotations and generates readable code
- Orika — bytecode-generation mapper; MapStruct's compile-time approach is simpler to debug
- JMapper — annotation-based but less actively maintained; MapStruct has broader community support
- Manual mapping — always works but tedious; MapStruct automates the boilerplate while remaining transparent
FAQ
Q: Does MapStruct work with Kotlin?
A: Yes. Use kapt or ksp as the annotation processing tool in your Kotlin build. MapStruct generates Java code that Kotlin calls seamlessly.
Q: How does MapStruct handle nested object mapping? A: It maps nested beans automatically if a mapper method exists for the nested type, or you can define one in the same interface.
Q: Can I customize individual field mappings?
A: Yes. Use @Mapping(source = "fieldA", target = "fieldB") for name differences, or expression for computed values.
Q: What happens with unmapped fields?
A: By default MapStruct warns. Set unmappedTargetPolicy = ERROR to enforce complete mappings at compile time.