Skip to content

Support for optional subtype-only source properties #2438

Description

@mjustin

My source type is a superclass with a certain set of properties, with a subclass that adds additional properties. My target type contains properties to be mapped from the superclass, as well as some optional properties to be mapped if the source is an instance of the subclass. It would be convenient to be able to be able to express this mapping relationship in a single annotation-based mapping method, rather than using multiple mapping methods with a custom mapping method to tie them together.

This is certainly related to #131, and possibly involves the same solution. The difference is that that issue concerns mapping to different target types based on the source type, whereas this involves mapping different target types to a single source type, with optional fields for subclasses.

Example

Types

public class Source {
    private String property1;
    private String property2;
    private String property3;

    // Getters, setters, & constructors omitted for brevity
}

public class SourceSubclass extends Source {
    private String subclassProperty;
    private String target5;

    // Getters, setters, & constructors omitted for brevity
}

public class Target {
    private String target1;
    private String target2;
    private String target3;
    private String target4;
    private String target5;

    // Getters, setters, & constructors omitted for brevity
}

Mapper

This is an solution to the problem using the features currently available in MapStruct.

@Mapper
public interface SourceMapper {
    default Target map(Source source) {
        if (source instanceof SourceSubclass) {
            return mapSubclass((SourceSubclass) source);
        } else {
            return mapSuperclass(source);
        }
    }

    @Mapping(target = "target1", source = "property1")
    @Mapping(target = "target2", source = "property2")
    @Mapping(target = "target3", source = "property3")
    @Mapping(target = "target4", expression = "java(null)")
    @Mapping(target = "target5", expression = "java(null)")
    Target mapSuperclass(Source source);

    @InheritConfiguration(name = "mapSuperclass")
    @Mapping(target = "target4", source = "subclassProperty")
    @Mapping(target = "target5") // Have to declare in order to override with default behavior
    Target mapSubclass(SourceSubclass source);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions