Constructor required a bean type that could not be found

Viewed 1506

I'm currently following a course on Spring Boot and making a Reddit clone. https://www.youtube.com/watch?v=DKlTBBuc32c

During the course, we have a service that uses Mapstruc to map a DTO.

My issue is that when I try to inject the mapper into the service, Spring cannot find the class and gives error:

Parameter 1 of constructor in com.subreddit.service.SubredditService required a bean of type 'com.subreddit.mapper.SubredditMapper' that could not be found.

Consider defining a bean of type 'com.subreddit.mapper.SubredditMapper' in your configuration.

Here is the service:

package com.subreddit.service;

import static java.util.stream.Collectors.toList;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.subreddit.dto.SubredditDto;
import com.subreddit.exceptions.SpringRedditException;
import com.subreddit.mapper.SubredditMapper;
import com.subreddit.model.Subreddit;
import com.subreddit.repository.SubredditRepository;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@AllArgsConstructor
@Slf4j

public class SubredditService {
private final SubredditRepository subredditRepository;
private SubredditMapper subredditMapper;

@Transactional
public SubredditDto save(SubredditDto subredditDto) {
    Subreddit save = subredditRepository.save(subredditMapper.mapDtoToSubreddit(subredditDto));
    subredditDto.setId(save.getId());
    return subredditDto;
}

@Transactional(readOnly = true)
public List<SubredditDto> getAll() {
    return subredditRepository.findAll()
            .stream()
            .map(subredditMapper::mapSubredditToDto)
            .collect(toList());
}

public SubredditDto getSubreddit(Long id) {
    Subreddit subreddit = subredditRepository.findById(id)
            .orElseThrow(() -> new SpringRedditException("No subreddit found with ID - " + id));
    return subredditMapper.mapSubredditToDto(subreddit);
}
}

Here is the mapper:

package com.subreddit.mapper;

import java.util.List;

import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

import com.subreddit.dto.SubredditDto;
import com.subreddit.model.Post;
import com.subreddit.model.Subreddit;

import lombok.RequiredArgsConstructor;


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

    @Mapping(target = "numberOfPosts", expression = "java(mapPosts(subreddit.getPosts()))")
    SubredditDto mapSubredditToDto(Subreddit subreddit);

    default Integer mapPosts(List<Post> numberOfPosts) {
        return numberOfPosts.size();
    }

    @InheritInverseConfiguration
    @Mapping(target = "posts", ignore = true)
    Subreddit mapDtoToSubreddit(SubredditDto subredditDto);
}
3 Answers

Defining interface SubredditMapper is not sufficient. To create an inject a bean, you need a class that implements it.

To make MapStruct generate such class, you need to activate annotation processor in IDE and in your your build tool. For every interface annotated with @Mapper the annotation processor will generate a class that implements this interface. At run time Spring will create an instance of this class, register it as a bean, and will inject it where you need it.

What should you do to resolve the problem?

  • Enable annotation processing in your IDE (IDEA, Eclipse, ...)
  • Check how your build tool (Gradle, Maven) is configured properly, e.g. check if annotation processing for MapStruct is activated, check if directories set properly

I saw their code. It's working. You didn't follow the steps well.

Take their code from here. Compare what have you done wrong.

Possible issue : The problem is with the package name. @ComponentScan is not able to register the bean from that package as you are unknowingly sending wrong package name.

I also followed that tutorial and the code works. Unfortunately one step is missing to make the SubredditMapper interface work.

The error is caused because Spring doesn't find the bean mapper (spring doesn't find the mapper implementation during the build) and mapstruct-processor is used to generate it.

In your pom.xml add the dependecy and annotationProcessorPaths path section to the configuration part of the maven-compiler-plugin plugin. After adding the, your pom file should look like this:

<dependency>
   <groupId>org.mapstruct</groupId>
   <artifactId>mapstruct</artifactId>
   <version>1.3.1.Final</version>  
</dependency>
...
<build>
    <plugins>
       ....
       <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.5.1</version>
          <configuration>
             <source>1.8</source>
             <target>1.8</target>
             <annotationProcessorPaths>
                <path>
                   <groupId>org.mapstruct</groupId>
                   <artifactId>mapstruct-processor</artifactId>
                   <version>1.3.1.Final</version>
                </path>
             </annotationProcessorPaths>
           </configuration>
       </plugin>
       ....

All you have to do is a clean install on the pom.xml file. This will generate the implementation class. Clean install steps:

  1. right click on pom.xml
  2. expand Run As
  3. select Maven build
  4. set Goals to the command clean install
  5. apply > run > close
Related