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.