I have a DTO that doesn't work with mapping
@Data
public class IndividualDTO {
private String passportNumber;
private String phoneNumber;
private UserDTO user;
@Data
public static class UserDTO {
@NotBlank
@Email
private String email;
private String secretKey;
private String firstName;
private String lastName;
private AddressDTO address;
}
@Data
public static class AddressDTO {
private String address;
private String city;
private String state;
private String zipCode;
private CountryDTO country;
}
@Data
public static class CountryDTO{
private String name;
}
}
I am trying to map using MapStruct in this way
IndividualMapper
@Mapper(componentModel = "spring", uses = {UserMapper.class, AddressMapper.class, CountryMapper.class})
public interface IndividualMapper {
IndividualMapper INSTANCE = Mappers.getMapper(IndividualMapper.class);
Individual toEntity(IndividualDTO dto);
IndividualDTO toDto(Individual entity);
}
AddressMapper
@Mapper(componentModel = "spring")
public interface AddressMapper {
Address toAddressEntity(IndividualDTO.AddressDTO addressDTO);
IndividualDTO.AddressDTO toAddressDto(Address address);
}
CountryMapper
@Mapper(componentModel = "spring")
public interface CountryMapper {
Country toCountryEntity(IndividualDTO.CountryDTO countryDTO);
IndividualDTO.CountryDTO toCountryDto(Country country);
}
UserMapper
@Mapper(componentModel = "spring")
public interface UserMapper {
User toUserEntity(IndividualDTO.UserDTO userDTO);
IndividualDTO.UserDTO toUserDto(User user);
}
As a result, I get:
@Component
public class IndividualMapperImpl implements IndividualMapper {
@Override
public Individual toEntity(IndividualDTO dto) {
if ( dto == null ) {
return null;
}
Individual individual = new Individual();
return individual;
}
@Override
public IndividualDTO toDto(Individual entity) {
if ( entity == null ) {
return null;
}
IndividualDTO individualDTO = new IndividualDTO();
return individualDTO;
}
}
According to the MapStruct documentation, everything should work, but unfortunately I ran into this problem.
MapStruct generated the IndividualMapperImpl class for me, which has no logic
According to the mapstruct FAQ, to use Lombok (1.18.16 version or newer) and Mapstruct together, you have to add lombok-binding
path to the config of the maven-compiler plugin:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
So please check pom file to make sure it is configured correctly according to the Mapstruct doc.
Additional comments:
IndividualMapper
), since you're using componentModel = "spring"
. You can simple autowire your mapper into other spring beans:@Service
public class SomeService {
@Autowired
private IndividualMapper individualMapper;
}
uses
attribute of the @Mapper
annotation only for IndividualMapper
with all mappers (even though it only needs to use the UserMapper
), and did not tell the other mappers which mappers they should use. This results in UserMapper
not using AddressMapper
, as intended (Check this in the generated mapperImpl-s). So add the uses
attribute with the appropriate values to the relevant mappers:@Mapper(componentModel = "spring", uses = UserMapper.class)
public interface IndividualMapper {
Individual toEntity(IndividualDTO dto);
IndividualDTO toDto(Individual entity);
}
@Mapper(componentModel = "spring", uses = AddressMapper.class)
public interface UserMapper {
Individual.User toUserEntity(IndividualDTO.UserDTO userDTO);
IndividualDTO.UserDTO toUserDto(Individual.User user);
}
// and so on for other mappers