Mapstruct - map property to property of object in a List

Viewed 297

Hello I have the following class:

public class BookWriteModel {
    List<PageWriteModel> pages;
}

public class Book {
    List<Page> pages;
}

public class PageWriteModel {
    Long pageNumber;
}

public class Page {
    Long pageNumber;
    Long userId;
}

public class User {
    Long userId;
}

My mapper as of now is something like this:

@Mapper( componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE )
public interface BookMapper {
    Book map(BookWriteModel bookWriteModel, User user);
}

What is the simpler way to map the userId to the userId on the Page?

Thanks

1 Answers

Solution 1: @AfterMapping method

@Mapper( componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE )
public interface BookMapper {
    BookMapper INSTANCE = Mappers.getMapper(BookMapper.class);

    Book map(BookWriteModel bookWriteModel, User user);

    @AfterMapping
    default void afterMap(@MappingTarget Book book, User user) {
        if (user != null) {
            for (Page page : book.pages) {
                page.userId = user.userId;
            }
        }
    }
}

Generated code:

@Component
public class BookMapperImpl implements BookMapper {
    @Override
    public Book map(BookWriteModel bookWriteModel, User user) {
        if ( bookWriteModel == null && user == null ) {
            return null;
        }
        Book book = new Book();
        if ( bookWriteModel != null ) {
            book.pages = pageWriteModelListToPageList( bookWriteModel.pages );
        }
        afterMap( book, user );
        return book;
    }

    protected Page pageWriteModelToPage(PageWriteModel pageWriteModel) {
        if ( pageWriteModel == null ) {
            return null;
        }
        Page page = new Page();
        page.pageNumber = pageWriteModel.pageNumber;
        return page;
    }

    protected List<Page> pageWriteModelListToPageList(List<PageWriteModel> list) {
        if ( list == null ) {
            return null;
        }
        List<Page> list1 = new ArrayList<Page>( list.size() );
        for ( PageWriteModel pageWriteModel : list ) {
            list1.add( pageWriteModelToPage( pageWriteModel ) );
        }
        return list1;
    }
}

Solution 2: using @Context togather @ObjectFactory

@Mapper( componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE )
public interface BookMapper {
    BookMapper INSTANCE = Mappers.getMapper(BookMapper.class);

    Book map(BookWriteModel bookWriteModel, @Context User user);

    @ObjectFactory
    default Page create(@Context User user) {
        Page page = new Page();
        if (user != null) {
            page.userId = user.userId;
        }
        return page;
    }
}

Generated code:

@Component
public class BookMapperImpl implements BookMapper {
    @Override
    public Book map(BookWriteModel bookWriteModel, User user) {
        if ( bookWriteModel == null ) {
            return null;
        }
        Book book = new Book();
        book.pages = pageWriteModelListToPageList( bookWriteModel.pages, user );
        return book;
    }

    protected Page pageWriteModelToPage(PageWriteModel pageWriteModel, User user) {
        if ( pageWriteModel == null ) {
            return null;
        }
        Page page = create( user );
        page.pageNumber = pageWriteModel.pageNumber;
        return page;
    }

    protected List<Page> pageWriteModelListToPageList(List<PageWriteModel> list, User user) {
        if ( list == null ) {
            return null;
        }
        List<Page> list1 = new ArrayList<Page>( list.size() );
        for ( PageWriteModel pageWriteModel : list ) {
            list1.add( pageWriteModelToPage( pageWriteModel, user ) );
        }
        return list1;
    }
}

Solution 3: using @Context togather @ObjectFactory and additional mapping method

@Mapper( componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface BookMapper {
    BookMapper INSTANCE = Mappers.getMapper(BookMapper.class);

    Book map(BookWriteModel bookWriteModel, @Context User user);
    
    Page map(User user);

    @ObjectFactory
    default Page create(@Context User user) {
        Page page = map(user);
        return page == null ? new Page() : page;
    }
}

Generated code:

@Component
public class BookMapperImpl implements BookMapper {
    @Override
    public Book map(BookWriteModel bookWriteModel, User user) {
        if ( bookWriteModel == null ) {
            return null;
        }
        Book book = new Book();
        book.pages = pageWriteModelListToPageList( bookWriteModel.pages, user );
        return book;
    }

    @Override
    public Page map(User user) {
        if ( user == null ) {
            return null;
        }
        Page page = new Page();
        page.userId = user.userId;
        return page;
    }

    protected Page pageWriteModelToPage(PageWriteModel pageWriteModel, User user) {
        if ( pageWriteModel == null ) {
            return null;
        }
        Page page = create( user );
        page.pageNumber = pageWriteModel.pageNumber;
        return page;
    }

    protected List<Page> pageWriteModelListToPageList(List<PageWriteModel> list, User user) {
        if ( list == null ) {
            return null;
        }
        List<Page> list1 = new ArrayList<Page>( list.size() );
        for ( PageWriteModel pageWriteModel : list ) {
            list1.add( pageWriteModelToPage( pageWriteModel, user ) );
        }
        return list1;
    }
}

Solution 4: @Context method as proxy to mapping method

@Mapper( componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface BookMapper {
    BookMapper INSTANCE = Mappers.getMapper(BookMapper.class);

    Book map(BookWriteModel bookWriteModel, @Context User user);

    Page map(PageWriteModel pageWriteModel, User user);

    default Page mapContext(PageWriteModel pageWriteModel, @Context User user) {
        return map(pageWriteModel, user);
    }
}

Generated code:

@Component
public class BookMapperImpl implements BookMapper {

    @Override
    public Book map(BookWriteModel bookWriteModel, User user) {
        if ( bookWriteModel == null ) {
            return null;
        }

        Book book = new Book();

        book.pages = pageWriteModelListToPageList( bookWriteModel.pages, user );

        return book;
    }

    @Override
    public Page map(PageWriteModel pageWriteModel, User user) {
        if ( pageWriteModel == null && user == null ) {
            return null;
        }

        Page page = new Page();

        if ( pageWriteModel != null ) {
            page.pageNumber = pageWriteModel.pageNumber;
        }
        if ( user != null ) {
            page.userId = user.userId;
        }
        return page;
    }

    protected List<Page> pageWriteModelListToPageList(List<PageWriteModel> list, User user) {
        if ( list == null ) {
            return null;
        }
        List<Page> list1 = new ArrayList<Page>( list.size() );
        for ( PageWriteModel pageWriteModel : list ) {
            list1.add( mapContext( pageWriteModel, user ) );
        }
        return list1;
    }
}

I think, Solution 4 is clear and preferable.

Related