2

I was following this JavaBrains tutorials of Spring Boot.

My project structure is as follows:

enter image description here

CourseApiApp.java:

@SpringBootApplication
@ComponentScan(basePackages = {
    "com.bloodynacho.rishab.topics"
})
@EntityScan("com.bloodynacho.rishab.topics")
public class CourseApiApp {

    public static void main(String[] args) {
        SpringApplication.run(CourseApiApp.class, args);
    }
}

TopicController.java:

@RestController
public class TopicController {

    @Autowired
    private TopicService topicService;

    @RequestMapping(
        value = "/topics"
    )
    public List<Topic> getAllTopcs() {
        return topicService.getAllTopics();
    }
}

TopicService.java:

@Service
public class TopicService {

    @Autowired
    private TopicRepository topicRepository;

    public List<Topic> getAllTopics() {
        List<Topic> topics = new ArrayList<>();
        this.topicRepository
            .findAll()
            .forEach(topics::add);
        return topics;
    }
}

Topic.java:

@Entity
public class Topic {
    @Id
    private String id;
    private String name;
    private String description;
}

TopicRepository.java:

@Repository
public interface TopicRepository extends CrudRepository<Topic, String>{
}

pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.apache.derby</groupId>
        <artifactId>derby</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

I was using the lombok @Getter, @Getter and @AllArgsConstructor in Topic.java but I removed it after reading one of the answers here.

I read this1, this2, this3

Still, I get

***************************
APPLICATION FAILED TO START
***************************

Description:
Field topicRepository in com.bloodynacho.rishab.topics.TopicService required a bean of type 'com.bloodynacho.rishab.topics.TopicRepository' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.bloodynacho.rishab.topics.TopicRepository' in your configuration.
Process finished with exit code 1

EDIT: I read this explaining how even without actually implementing the interface the @Autowired works. I understand the solution, but I don't understand how to solve my issue. Clearly, there is some problem with the way Spring Data is set up and configured (as mentioned in the answer)

coda
  • 2,188
  • 2
  • 22
  • 26
  • TopicRepository should not be an interface but a class. – best wishes Jun 17 '19 at 02:19
  • are you sure? If I do public class TopicRepository extends CrudRepository {} I get a compilation error in IntelliJ saying Class TopicRepository must either be declared abstract or implement abstract method save(S) in CrudRepository. Also, I checked the tutorial video, there also its interface and not a class. – coda Jun 17 '19 at 02:25
  • try creating a dummy method save(S) and make it a class. it should work. – best wishes Jun 17 '19 at 02:33
  • I did that but then it just starts telling me to one by one implement all the methods in interface CrudRepository. If I have to implement all the methods myself then what is the point of using it? Also, in the tutorial, he clearly says that CrudRepository has those functionalities built in for us. – coda Jun 17 '19 at 02:44
  • also, I think you are wrong, please go over this answer https://stackoverflow.com/questions/43424149/how-does-the-autowired-interface-which-extends-crudrepository-works-i-would – coda Jun 17 '19 at 02:45
  • Try to remove `@ComponentScan` and `@EntityScan`. – LHCHIN Jun 17 '19 at 03:05
  • 1
    @LHCHIN that would remove the compilation error but thats wrong, cause `@SpringBootApplication` looks for packages only in the package where it is used, so removing `@ComponentScan` basically means, Spring is unaware of Topic and Course package, see this answer https://stackoverflow.com/questions/40384056/consider-defining-a-bean-of-type-package-in-your-configuration-spring-boot#answer-40388609 – coda Jun 17 '19 at 03:12
  • 3
    Sure, I mean that if you set your package name of main class to be `com.bloodynacho.rishab`, then you don't need to add those two annotations. And in my opinion, the package name of main class is supposed to be root name of other packages. – LHCHIN Jun 17 '19 at 03:24
  • @LHCHIN that fixed the issue. If you want to, write the comment as an answer. I will upvote and accept – coda Jun 17 '19 at 04:00
  • Hi, I have posted the answer and it's my pleasure to help you. – LHCHIN Jun 17 '19 at 05:15

1 Answers1

3

Because if your other packages hierarchies are below your main application with the @SpringBootApplication annotation, you’re covered by implicit components scan.

Therefore, one simple solution can be done by following 2 steps:

  1. Rename the package of main class to be com.bloodynacho.rishab.
    (That is what I suggest that the complete package name of main app. is supposed to be root of other packages.)
  2. Remove @ComponentScan and @EntityScan annotation.
    (Although @ComponentScan is different from @EntityScan, it can be also removed in my experience.)
LHCHIN
  • 3,679
  • 2
  • 16
  • 34