Chapter 5.5☕ 14 min read

Entity-DTO Mapping

Stop writing dto.setName(entity.getName()). MapStruct does it for you.

01The Concept: Object Translation

The Movie Subtitle Translation Analogy:

Imagine a Telugu movie being released globally. You don’t hire a human to sit in the theater and manually translate every dialogue into English on a whiteboard. That’s slow and prone to errors. Instead, you use a translation software that takes the Telugu script and automatically generates an English subtitle file.

MapStruct is that translation software for Java objects. You tell it “Map UserEntity to UserResponseDTO”, and at compile-time, it generates the Java code to copy the matching fields automatically.

02Technical Explanation
  1. MapStruct: A code-generation tool. You create an interface, and MapStruct generates the implementation class during Maven compilation.
  2. @Mapper: Marks the interface as a MapStruct mapper.
  3. Matching Fields: MapStruct automatically maps fields that have the exact same name and data type (e.g., String name maps to String name).
03Full Working Code: MapStruct Setup
<!-- pom.xml Dependencies -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<!-- pom.xml Build Plugins -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
package com.devinhyderabad;

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

// componentModel = "spring" makes this a Spring Bean
@Mapper(componentModel = "spring")
public interface UserMapper {

UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

// MapStruct generates the code to copy fields from Entity to DTO
UserResponseDTO toDto(UserEntity entity);

// MapStruct can also map DTO to Entity (for POST requests)
UserEntity toEntity(UserResponseDTO dto);
}
04Using the Mapper in the Service
package com.devinhyderabad;

import org.springframework.stereotype.Service;

@Service
public class UserService {

private final UserRepository userRepository;
private final UserMapper userMapper; // Injected by Spring

public UserService(UserRepository userRepository, UserMapper userMapper) {
this.userRepository = userRepository;
this.userMapper = userMapper;
}

public UserResponseDTO getUser(Long id) {
UserEntity entity = userRepository.findById(id).orElseThrow();
// The magic line! No manual dto.setName(entity.getName())
return userMapper.toDto(entity);
}
}
05Why It Matters / Interview Note

Interview Question: “What is the difference between MapStruct and ModelMapper?”

Answer: ModelMapper uses Java Reflection at runtime to copy fields. This is slower but requires zero setup. MapStruct generates plain Java code at compile-time. Because it is just normal Java code executing at runtime, it is exponentially faster than ModelMapper and catches typos at compile time.

Enterprise Note: MapStruct and Lombok often fight over the annotation processor. To make them work together, you must declare the Lombok annotation processor (lombok-mapstruct-binding) inside the maven-compiler-plugin configuration in your pom.xml.

Key Takeaways

  • ✅ MapStruct generates Entity-to-DTO mapping code at compile-time
  • ✅ @Mapper(componentModel = "spring") makes it a Spring Bean
  • ✅ MapStruct is faster than ModelMapper (no runtime reflection)
  • ✅ MapStruct + Lombok need careful pom.xml annotation processor configuration