'Spring Boot / MapStruct: Parameter 1 of constructor required a bean... Consider defining a bean of type

I don't know so much about Java, but I thought it should be enough to manage this little task...

I'm building a microservice, which provides Songs and list of songs via several Rest-Endpoints. But it doesn't just return a song when called, it also has to contact another service and enhance the song object with additional information. For this I implemented a Dto-Class and I use mapstruct to handle logic behind. I also did this in other projects with no problems. But now I'm struggling, because of this error, which I don't know how to solve - it says:

Parameter 1 of constructor in mk.microservices.songsservice.services.SongServiceImpl required a bean of type 'mk.microservices.songsservice.web.mapper.SongMapper' that could not be found.

Action:

Consider defining a bean of type 'mk.microservices.songsservice.web.mapper.SongMapper' in your configuration.

Here are excerpts from my code:

SongServiceImpl

import lombok.RequiredArgsConstructor;
import mk.microservices.songsservice.domain.Song;
import mk.microservices.songsservice.repositories.SongRepository;
import mk.microservices.songsservice.web.mapper.SongMapper;
import mk.microservices.songsservice.web.model.SongDto;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@RequiredArgsConstructor
@Service
public class SongServiceImpl implements SongService {

    private final SongRepository songRepository;
    private final SongMapper songMapper;

    @Override
    public SongDto getSongById(Integer id) {
        return songMapper.songToSongDto(songRepository.findById(id));
    }

    @Override
    public List<Song> getAllSongs() {
        return songRepository.findAll();
    }
....
}

SongMapper

import org.mapstruct.DecoratedWith;

import java.util.Optional;

@MapStruct
@DecoratedWith(SongMapperDecorator.class)
public interface SongMapper {

    SongDto songToSongDto(Optional<Song> song);
    SongDto songToSongDtoWithSongInfo(Song song);
    Song songDtoToSong(SongDto songDto);
}

SongMapperDecorator

import org.springframework.beans.factory.annotation.Autowired;

import java.util.Optional;

public class SongMapperDecorator implements SongMapper {

    private SongInfoService songInfoService;
    private SongMapper mapper;

    @Autowired
    public void setMapper(SongMapper songMapper) { this.mapper = songMapper; }

    @Override
    public SongDto songToSongDto(Optional<Song> song) {
        return mapper.songToSongDto(song);
    }

    @Override
    public SongDto songToSongDtoWithSongInfo(Song song) {
        SongDto songDto = mapper.songToSongDto(Optional.ofNullable(song));
        SongInfo songInfo = songInfoService.getSongInfoBySongId(song.getId());
        songDto.setDescription(songInfo.getDescription());
        return songDto;
    }

    @Override
    public Song songDtoToSong(SongDto songDto) {
        return mapper.songDtoToSong(songDto);
    }
}

Also did a clean, validate and compile without any errors. But when I did the verify, I got this:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project songs-service: Resolution of annotationProcessorPath dependencies failed: Missing: [ERROR] ---------- [ERROR] 1) org.mapstruct:mapstruct-processor:jar:1.4.2

My POM looks like this:

The dependency for mapstruct:

<dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.4.2.Final</version>
</dependency>

And the plugin for enabling mapstruct and lombok working together:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
        <configuration>
            <annotationProcessorPaths>
                <path>
                    <groupId>org.mapstruct</groupId>
                    <artifactId>mapstruct-processor</artifactId>
                    <version>${mapstruct.version}</version>
                </path>
                <path>
                     <groupId>org.projectlombok</groupId>
                     <artifactId>lombok</artifactId>
                     <version>${lombok.version}</version>
                 </path>
            </annotationProcessorPaths>
            <compilerArgs>
                <compilerArg>
                    -Amapstruct.defaultComponentModel=spring
                </compilerArg>
            </compilerArgs>
        </configuration>
    </plugin>

Would be very glad, if someone could help me solving this. Already googled a lot and didn't find anything useful yet.

Br, Mic



Solution 1:[1]

As it is clear from the error the SongServiceImpl requires a bean SongMapper but Mapstruct do not generate a spring bean by default. i,e it will not add @Component annotation in the generated class, so we need to explicitly mention to generate a class that can be used to create spring bean.

so instead of @MapStruct use @Mapper(componentModel = "spring") in the mapper interface.

Solution 2:[2]

Solved it finally, changed the mapstruct version in my POM to 1.4.2.Final (instead of just 1.4.2). Now it works...

Got the hint frome Mapstruct-Documentation here...

Solution 3:[3]

Solved this finally. I used this configuration (mapstruct + lombok) Also installed m2e-apt plugin in eclipse.

pom.xml

     <dependency>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct</artifactId>
                <version>1.4.2.Final</version>
            </dependency>
            <dependency>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>1.4.2.Final</version>
            </dependency>
------------------------------------------------------------
                    <configuration>
                        <source>1.8</source> <!-- depending on your project -->
                        <target>1.8</target> <!-- depending on your project -->
                        <annotationProcessorPaths>
                            <path>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                                <version>${lombok.version}</version>
                            </path>
                            <!-- other annotation processors -->
                        </annotationProcessorPaths>
                        <compilerArgs>
                            <compilerArg>
                                -Amapstruct.defaultComponentModel=spring
                            </compilerArg>
                        </compilerArgs>
                    </configuration>

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 Hemanth Kumar
Solution 2
Solution 3 Ambrish Rajput