CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-mapstruct--mapstruct

Java annotation processor for the generation of type-safe bean mappers

Pending
Overview
Eval results
Files

configuration-inheritance.mddocs/

Configuration and Inheritance

Configuration sharing, inheritance patterns, and qualifier systems for managing complex mapping scenarios and reusable mapping configurations.

Capabilities

Configuration Inheritance

Methods for inheriting configuration from other mapping methods to reduce duplication and maintain consistency.

/**
 * Advises the code generator to apply the configuration from another mapping method to the annotated method as well.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
@interface InheritConfiguration {
    /** Name of the method to inherit the configuration from */
    String name() default "";
}

/**
 * Advises the code generator to apply the inverse configuration of the method specified via name().
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
@interface InheritInverseConfiguration {
    /** Name of the method to inherit the inverse configuration from */
    String name() default "";
}

Usage Examples:

@Mapper
public interface ConfigurationInheritanceMapper {
    // Base mapping configuration
    @Mapping(source = "firstName", target = "name")
    @Mapping(source = "birthDate", target = "dateOfBirth", dateFormat = "yyyy-MM-dd")
    @Mapping(target = "id", ignore = true)
    @Mapping(target = "version", constant = "1.0")
    PersonDto toPersonDto(Person person);
    
    // Inherit all configuration from toPersonDto
    @InheritConfiguration(name = "toPersonDto")
    @Mapping(target = "email", source = "emailAddress")  // Additional mapping
    DetailedPersonDto toDetailedPersonDto(Person person);
    
    // Inherit inverse configuration (for reverse mapping)
    @InheritInverseConfiguration(name = "toPersonDto")
    Person toPerson(PersonDto personDto);
    
    // Inherit and override specific mappings
    @InheritConfiguration(name = "toPersonDto")
    @Mapping(target = "name", source = "fullName")  // Override inherited mapping
    PersonSummaryDto toPersonSummaryDto(Person person);
}

Mapping Inheritance Strategies

Strategies for controlling how configuration inheritance works in complex scenarios.

/**
 * Strategy for applying method-level configuration annotations of prototype methods.
 */
enum MappingInheritanceStrategy {
    /** Only inherit configuration that is explicitly configured */
    EXPLICIT,
    
    /** Auto-inherit configuration from methods in @MapperConfig interface */
    AUTO_INHERIT_FROM_CONFIG,
    
    /** Auto-inherit reverse configuration from @MapperConfig interface */
    AUTO_INHERIT_REVERSE_FROM_CONFIG,
    
    /** Auto-inherit all configuration from @MapperConfig interface */
    AUTO_INHERIT_ALL_FROM_CONFIG
}

Usage Examples:

// Configuration interface
@MapperConfig(mappingInheritanceStrategy = MappingInheritanceStrategy.AUTO_INHERIT_FROM_CONFIG)
public interface BaseConfig {
    @Mapping(source = "createdAt", target = "created", dateFormat = "yyyy-MM-dd HH:mm:ss")
    @Mapping(source = "updatedAt", target = "modified", dateFormat = "yyyy-MM-dd HH:mm:ss")
    AuditableDto toAuditableDto(AuditableEntity entity);
}

// Mapper using the configuration
@Mapper(config = BaseConfig.class)
public interface UserMapper {
    // Automatically inherits audit field mappings from BaseConfig
    UserDto toUserDto(User user);
    
    // Explicit inheritance override
    @InheritConfiguration(name = "toAuditableDto")
    @Mapping(source = "email", target = "emailAddress")
    DetailedUserDto toDetailedUserDto(User user);
}

Qualifier System

Annotation-based and string-based qualifiers for precise mapping method selection.

/**
 * Marks an annotation as a qualifier for mapping method selection.
 */
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.CLASS)
@interface Qualifier {
}

/**
 * String-based qualifier for mapping method selection.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.CLASS)
@interface Named {
    /** Qualifier name */
    String value();
}

Usage Examples:

// Custom qualifier annotations
@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface ToDto {
}

@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface ToEntity {
}

@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface GermanTranslation {
}

@Mapper
public abstract class QualifierMapper {
    // Main mapping methods
    @Mapping(source = "title", target = "name", qualifiedBy = ToDto.class)
    public abstract BookDto toBookDto(Book book);
    
    @Mapping(source = "name", target = "title", qualifiedBy = ToEntity.class)
    public abstract Book toBook(BookDto bookDto);
    
    // Qualified helper methods
    @ToDto
    protected String formatTitleForDto(String title) {
        return title != null ? title.toUpperCase() : null;
    }
    
    @ToEntity
    protected String formatTitleForEntity(String name) {
        return name != null ? name.toLowerCase() : null;
    }
    
    // String-based qualifiers
    @Named("germanTitle")
    protected String translateToGerman(String title) {
        // Translation logic
        return translateService.translate(title, "de");
    }
    
    @Named("englishTitle")
    protected String translateToEnglish(String titel) {
        return translateService.translate(titel, "en");
    }
    
    // Using string qualifiers
    @Mapping(source = "title", target = "germanTitle", qualifiedByName = "germanTitle")
    @Mapping(source = "title", target = "englishTitle")
    MultiLanguageBookDto toMultiLanguageBookDto(Book book);
}

Advanced Inheritance Patterns

Complex inheritance scenarios with multiple configuration sources.

Usage Examples:

// Base configuration with common mappings
@MapperConfig
public interface CommonConfig {
    @Mapping(target = "id", ignore = true)
    @Mapping(target = "version", constant = "1.0")
    @Mapping(source = "lastModified", target = "updated", dateFormat = "yyyy-MM-dd")
    BaseDto toBaseDto(BaseEntity entity);
}

// Specific configuration extending base
@MapperConfig(uses = CommonConfig.class)
public interface AuditConfig {
    @InheritConfiguration(name = "toBaseDto")
    @Mapping(source = "createdBy", target = "creator")
    @Mapping(source = "modifiedBy", target = "modifier")
    AuditableDto toAuditableDto(AuditableEntity entity);
}

// Mapper with multiple inheritance levels
@Mapper(config = AuditConfig.class)
public interface DocumentMapper {
    // Inherits from AuditConfig -> CommonConfig chain
    @InheritConfiguration(name = "toAuditableDto")
    @Mapping(source = "content", target = "body")
    @Mapping(source = "title", target = "heading")
    DocumentDto toDocumentDto(Document document);
    
    // Selective inheritance with overrides
    @InheritConfiguration(name = "toAuditableDto")
    @Mapping(target = "version", constant = "2.0")  // Override inherited constant
    @Mapping(target = "summary", expression = "java(document.getContent().substring(0, 100))")
    DocumentSummaryDto toDocumentSummaryDto(Document document);
}

Conditional Configuration Inheritance

Using conditions with inherited configurations.

Usage Examples:

@Mapper
public abstract class ConditionalInheritanceMapper {
    // Base mapping with conditions
    @Mapping(target = "email", conditionQualifiedByName = "hasValidEmail")
    @Mapping(target = "phone", conditionQualifiedByName = "hasValidPhone")
    public abstract ContactDto toContactDto(Person person);
    
    // Inherit conditions and add new ones
    @InheritConfiguration(name = "toContactDto")
    @Mapping(target = "address", conditionExpression = "java(person.getAddress() != null)")
    public abstract DetailedContactDto toDetailedContactDto(Person person);
    
    // Condition methods
    @Condition
    @Named("hasValidEmail")
    protected boolean hasValidEmail(String email) {
        return email != null && email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
    }
    
    @Condition
    @Named("hasValidPhone")
    protected boolean hasValidPhone(String phone) {
        return phone != null && phone.matches("\\d{10}");
    }
}

Configuration with Component Models

Inheritance patterns in dependency injection environments.

Usage Examples:

// Spring configuration
@MapperConfig(componentModel = "spring")
public interface SpringConfig {
    @Mapping(source = "createdAt", target = "timestamp", dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    TimestampedDto toTimestampedDto(TimestampedEntity entity);
}

// Spring mappers using shared configuration
@Mapper(config = SpringConfig.class)
public interface SpringUserMapper {
    @InheritConfiguration
    UserDto toUserDto(User user);
}

@Mapper(config = SpringConfig.class)  
public interface SpringOrderMapper {
    @InheritConfiguration
    OrderDto toOrderDto(Order order);
}

// CDI configuration
@MapperConfig(componentModel = "cdi")
public interface CdiConfig {
    @Mapping(target = "id", ignore = true)
    @Mapping(source = "status", target = "state")
    ProcessableDto toProcessableDto(ProcessableEntity entity);
}

@Mapper(config = CdiConfig.class)
public interface CdiDocumentMapper {
    @InheritConfiguration
    @Mapping(source = "title", target = "documentTitle")
    DocumentDto toDocumentDto(Document document);
}

Cross-Mapper Configuration Sharing

Sharing configuration across multiple mapper interfaces.

Usage Examples:

// Shared mapping utilities
@MapperConfig
public interface MappingUtils {
    @Named("formatCurrency")
    default String formatCurrency(BigDecimal amount) {
        return NumberFormat.getCurrencyInstance().format(amount);
    }
    
    @Named("parseDate")
    default LocalDate parseDate(String dateString) {
        return dateString != null ? LocalDate.parse(dateString) : null;
    }
    
    @Named("formatDate")
    default String formatDate(LocalDate date) {
        return date != null ? date.format(DateTimeFormatter.ISO_LOCAL_DATE) : null;
    }
}

// Multiple mappers using shared utilities
@Mapper(config = MappingUtils.class)
public interface ProductMapper {
    @Mapping(source = "price", target = "formattedPrice", qualifiedByName = "formatCurrency")
    @Mapping(source = "releaseDate", target = "releaseDateString", qualifiedByName = "formatDate")
    ProductDto toProductDto(Product product);
}

@Mapper(config = MappingUtils.class)
public interface OrderMapper {
    @Mapping(source = "total", target = "totalFormatted", qualifiedByName = "formatCurrency")
    @Mapping(source = "orderDateString", target = "orderDate", qualifiedByName = "parseDate")
    OrderDto toOrderDto(Order order);
}

// Composite configuration
@MapperConfig(uses = {MappingUtils.class})
public interface EnhancedConfig {
    @InheritConfiguration
    @Mapping(target = "createdBy", expression = "java(getCurrentUser())")
    AuditableDto toAuditableDto(AuditableEntity entity);
    
    default String getCurrentUser() {
        return SecurityContextHolder.getContext().getAuthentication().getName();
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-mapstruct--mapstruct

docs

advanced-features.md

collection-mapping.md

configuration-inheritance.md

core-mapping.md

enum-mapping.md

index.md

lifecycle-customization.md

tile.json