MapStruct's imports attribute brings external types into scope for generated mappers. This guide focuses purely on the working code demonstrating imports in action.
Domain Model
Abstract base entity:
package com.example.domain;
public abstract class AbstractBaseEntity {
private Long id;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public abstract String getStatus();
}
Source entity:
package com.example.domain;
public class UserEntity extends AbstractBaseEntity {
private String username;
private String email;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
@Override
public String getStatus() { return "ACTIVE"; }
}
Target DTO:
package com.example.dto;
public class UserDto {
private Long id;
private String username;
private String email;
private String statusInfo;
// getters/setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getStatusInfo() { return statusInfo; }
public void setStatusInfo(String statusInfo) { this.statusInfo = statusInfo; }
@Override
public String toString() {
return "UserDto{id=" + id + ", username='" + username + "', statusInfo='" + statusInfo + "'}";
}
}
Mapper with Imports
package com.example.mapper;
import com.example.dto.UserDto;
import com.example.domain.UserEntity;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import java.util.List;
@Mapper(imports = com.example.domain.AbstractBaseEntity.class)
public interface UserMapper {
@Mapping(target = "id", source = "id")
@Mapping(target = "username", source = "username")
@Mapping(target = "email", source = "email")
@Mapping(target = "statusInfo", expression = "java( ((AbstractBaseEntity) entity).getStatus() + \" (processed)\")")
UserDto toDto(UserEntity entity);
List<UserDto> toDtos(List<UserEntity> entities);
}
Usage Code
package com.example.demo;
import com.example.domain.UserEntity;
import com.example.dto.UserDto;
import com.example.mapper.UserMapper;
import org.mapstruct.factory.Mappers;
public class MapStructDemo {
private static final UserMapper MAPPER = Mappers.getMapper(UserMapper.class);
public static void main(String[] args) {
UserEntity entity = new UserEntity();
entity.setId(42L);
entity.setUsername("john_doe");
entity.setEmail("john@example.com");
UserDto dto = MAPPER.toDto(entity);
System.out.println("Mapped DTO: " + dto);
}
}
Generated Code Insight
MapStruct generates UserMapperImpl with automatic import:
package com.example.mapper;
import com.example.domain.AbstractBaseEntity; // Added by imports attribute
import com.example.domain.UserEntity;
import com.example.dto.UserDto;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.processing.Generated;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
comments = "version: 1.6.3, compiler: IncrementalProcessingEnvironment from gradle-language-java-9.2.0.jar, environment: Java 25 (Oracle Corporation)"
)
public class UserMapperImpl implements UserMapper {
@Override
public UserDto toDto(UserEntity entity) {
if ( entity == null ) {
return null;
}
UserDto userDto = new UserDto();
userDto.setId( entity.getId() );
userDto.setUsername( entity.getUsername() );
userDto.setEmail( entity.getEmail() );
userDto.setStatusInfo( ((AbstractBaseEntity) entity).getStatus() + " (processed)" );
return userDto;
}
@Override
public List<UserDto> toDtos(List<UserEntity> entities) {
if ( entities == null ) {
return null;
}
List<UserDto> list = new ArrayList<UserDto>( entities.size() );
for ( UserEntity userEntity : entities ) {
list.add( toDto( userEntity ) );
}
return list;
}
}
Why Imports Are Required
❌ Without imports attribute:
// GENERATED CODE FAILS TO COMPILE:
// error: cannot find symbol
// symbol: class AbstractBaseEntity
// ((AbstractBaseEntity) entity).getStatus()
✅ With imports = AbstractBaseEntity.class:
// GENERATED CODE WORKS PERFECTLY:
// import com.example.domain.AbstractBaseEntity;
// ((AbstractBaseEntity) entity).getStatus() ✓
Multiple Imports Pattern
@Mapper(imports = {
com.example.domain.AbstractBaseEntity.class,
java.time.LocalDateTime.class
})
public interface AdvancedUserMapper {
@Mapping(target = "createdAt", expression = "java(LocalDateTime.now())")
@Mapping(target = "fullInfo", expression = "java(entity.getUsername() + \" <\" + ((AbstractBaseEntity)entity).getStatus() + \">\")")
UserDto toDto(UserEntity entity);
}
The imports attribute eliminates compilation errors when mappings reference types across packages or inheritance hierarchies.
Leave a Reply