Reputation: 405
I have two classes
@Entity
class Author {
@Id
private Long id;
private String authorName;
@OneToMany(mappedBy = "author")
private List<Book> authorBooks;
}
@Entity
class Book {
@Id
private Long id;
private String bookTitle;
@ManyToOne
@JoinColumn(name = "id")
private Author bookAuthor;
}
and I need to map incoming requests to the following dto class:
class AuthorRequest {
private String authorRequestName;
private List<String> authorRequestBooks;
}
I've implemented a simple dto interface with MapStruct
@Mapper
public interface AuthorMapper {
@Mapping(target = "authorName", source = "request.authorRequestName")
Author map(AuthorRequest request);
However, I also need to be able to create Book
object from each book title coming as a String
, as well as to set reference to the Author
object in each book while I'm still in the process of creating Author
. Something like this
public class AuthorMapperImpl implements AuthorMapper {
@Override
public Author map(AuthorRequest request) {
Author author = new Author();
author.setAuthorName(request.getAuthorRequestName());
author.mapBooks(request.getAuthorRequestBooks(), author);
return author;
}
private List<Book> mapBooks(List<String> authorRequestBooks, Author author) {
List<Book> books = new ArrayList<>();
for (String title : authorRequestBooks) {
Book book = new Book();
book.setBookAuthor(author);
book.setBookTitle(title);
books.add(book);
}
}
return books;
}
}
Is it possible to do using MapStruct?
Upvotes: 1
Views: 1720
Reputation: 3
Try to check this exapmle with qualifier.
https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-iterable-to-non-iterable
Upvotes: 0
Reputation: 21461
You can achieve this using a combination of lifecycle methods, @Context
and custom mapping.
@Context
will be used to keep track of the currently mapped author.
A solution can look like:
public class AuthorMappingContext {
protected Author currentAuthor;
@BeforeMapping
public void startMapping(@MappingTarget Author author) {
this.currentAuthor = author;
}
@AfterMapping
public void afterMapping(@MappingTarget Author author) {
this.currentAuthor = null;
}
}
and your mapper will look like:
@Mapper
public interface AuthorMapper {
@Mapping(target = "authorName", source = "request.authorRequestName")
@Mapping(target = "authorBooks", source = "authorRequestBooks")
Author map(AuthorRequest request, @Context AuthorMappingContext context);
default Book mapBook(String bookTitle, @Context AuthorMappingContext context) {
Book book = new Book();
book.setBookTitle(bookTitle);
book.setBookAuthor(context.getCurrentAuthor());
return book;
}
}
The mapBook
method is needed to tell MapStruct how to map from a String
to a Book
.
Upvotes: 1