Home > Software engineering >  MapStruct - mapping method from iterable to non-iterable
MapStruct - mapping method from iterable to non-iterable

Time:10-25

I have been working with MapStruct some days now and haven't yet achieved what i need.

As part of the exercises with Spring, I am writing a small app that will display information about the movies (title, description, director, etc.) and additionally the movie category. Therefore, I created an additional Entity called Category, so that (e.g. an admin) could add or remove individual category names.

Movie Entity:

public class Movie {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String content;
    private String director;
    private int year;
    @ManyToMany
    @Column(nullable = false)
    private List<Category> category;
    private LocalDate createdAt;
}

Category Entity

public class Category {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String categoryName;
    private LocalDate createdAt;
}

I packed it all into MapStruct and DTOs.

MovieDTORequest.java

public class MovieDTORequest {
    private String title;
    private String content;
    private String director;
    private List<Category> category;
    private int year;
}

MovieDTOResponse.java

public class MovieDTOResponse {
    private String title;
    private String content;
    private String director;
    private String categoryName; 
    private int year;
    private LocalDate createdAt;
}

And MovieMapper.java

@Mapper(componentModel = "spring")
public interface MovieMapper {

    @Mapping(target = "categoryName", source = "category")
    MovieDTOResponse movieToMovieDTO(Movie movie);

    @Mapping(target = "id", source = "title")
    @Mapping(target = "createdAt", constant = "")
    Movie movieRequestToMovie(MovieDTORequest request);

    @Mapping(target = "id", source = "title")
    @Mapping(target = "createdAt", constant = "")
    void updateMovie(MovieDTORequest request, @MappingTarget Movie target);

    String map(List<Category> value);
}

However, I have a problem with Mapper. First, I got the error:

"Can't map property "List<Category> category" to "String categoryName". Consider to declare/implement a mapping method: "String map(List<Category> value)"

and when I wrote it in Mapper, I have one more error:

Can't generate mapping method from iterable type from java stdlib to non-iterable type.

I am asking for help, because I am already lost.

CodePudding user response:

You should define default implementation for String map(List<Category> value) inside MovieMapper interface, what would Mapstruct use to map property List<Category> category to String categoryName. For example:

@Mapper(componentModel = "spring")
public interface MovieMapper {

    @Mapping(target = "categoryName", source = "category")
    MovieDTOResponse movieToMovieDTO(Movie movie);

    @Mapping(target = "id", source = "title")
    @Mapping(target = "createdAt", constant = "")
    Movie movieRequestToMovie(MovieDTORequest request);

    @Mapping(target = "id", source = "title")
    @Mapping(target = "createdAt", constant = "")
    void updateMovie(MovieDTORequest request, @MappingTarget Movie target);

    default String map(List<Category> value){
        //TODO: Implement your own logic that determines categoryName
        return "Movie Categories";
    }
}
  • Related