'How to use multiple properties from an object and map it to a single one in an other?

I need to map two objects together using both custom and regular mapping. Some properties are explicit and don't need any modifications, just mapping (because they don't have the same name), but some others need transformations.

Let's say I have two objects :

public class A {
    String id;
    String name;
    String firstname;
}

public class B {
    String nameB;
    String firstnameB;
}

And an interface :

@Mapper
public interface MyMapper {
    
    @Mappings({
        @Mapping(target="name", source="b.nameB"),
        @Mapping(target="firstname", source="b.firstnameB"),
        @Mapping(target="id", source="?", qualifiedByName="createId")
    })
    A BToA(B b);

    @Named("createId")
    default String createId(? ?) {

        return nameB + firstnameB;
    }
}

In this interface I want to map A.id to B.nameB + B.firstnameB in a custom mapping method. I looked into the mapstruct documentation but I cannot figure out how to get multiple sources or just the B object as a source.

Is this possible ? If not how can I achieve it ?



Solution 1:[1]

Solution 1: Method qualifier

@Mapper
public interface MyMapper {

    @Mappings({
            @Mapping(target="name", source="bObject.nameB"),
            @Mapping(target="firstname", source="bObject.firstnameB"),
            @Mapping(target="id", source="bObject", qualifiedByName="createId")
    })
    A BToA(B bObject);

    @Named("createId")
    default String createId(B bObject) {
        return bObject.nameB + bObject.firstnameB;
    }
}

Generated code:

public class MyMapperImpl implements MyMapper {
    @Override
    public A BToA(B bObject) {
        if ( bObject == null ) {
            return null;
        }
        A a = new A();
        a.name = bObject.nameB;
        a.firstname = bObject.firstnameB;
        a.id = createId( bObject );
        return a;
    }
}

Solution 2: Expression

@Mapper
public interface MyMapper {
    @Mappings({
            @Mapping(target="name", source="bObject.nameB"),
            @Mapping(target="firstname", source="bObject.firstnameB"),
            @Mapping(target="id", expression = "java(bObject.nameB + bObject.firstnameB)")
    })
    A BToA(B bObject);
}

Generated code:

public class MyMapperImpl implements MyMapper {
    @Override
    public A BToA(B bObject) {
        if ( bObject == null ) {
            return null;
        }
        A a = new A();
        a.name = bObject.nameB;
        a.firstname = bObject.firstnameB;
        a.id = bObject.nameB + bObject.firstnameB;
        return a;
    }
}

Solution 3: AfterMapping annotation

@Mapper
public interface MyMapper {
    @Mappings({
            @Mapping(target="name", source="bObject.nameB"),
            @Mapping(target="firstname", source="bObject.firstnameB"),
    })
    A BToA(B bObject);

    @AfterMapping
    default void afterMapping(@MappingTarget A aObject, B bObject) {
        aObject.id = bObject.nameB + bObject.firstnameB;
    }
}

Generated code:

public class MyMapperImpl implements MyMapper {
    @Override
    public A BToA(B bObject) {
        if ( bObject == null ) {
            return null;
        }
        A a = new A();
        a.name = bObject.nameB;
        a.firstname = bObject.firstnameB;
        afterMapping( a, bObject );
        return a;
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1