javaspringspring-bootspring-jdbc

Spring can't find the Repository bean in the Service


I have a problem when launching the application :

Description:

Parameter 0 of constructor in com.backend.services.RoleService required a bean of type 'com.backend.repository.RoleRepository' that could not be found.


Action:

Consider defining a bean of type 'com.backend.repository.RoleRepository' in your configuration.

Has anyone experienced this problem?

Project structure:

com.backend

entity.Role

enums.ERole

repository.RoleRepository

services.RoleService

Its code

Application.yml (dev I using it)

spring:
  config:
    activate:
      on-profile: "dev"
  datasource:
    url: jdbc:mysql://localhost:3306/${MYSQL_DATABASE}
    username: ${MYSQL_USER}
    password: ${MYSQL_PASSWORD}
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true
    properties:
      hibernate:
        dialect: "org.hibernate.dialect.MySQL5InnoDBDialect"
  flyway:
    enabled: true
    url: jdbc:mysql://localhost:3306/${MYSQL_DATABASE}
    locations: classpath:db/migration
    user: ${MYSQL_USER}
    password: ${MYSQL_PASSWORD}
    create-schemas: true
    default-schema: ${MYSQL_DATABASE}
#logging:
#  level:
#    root: debug

jwtSecret: "superkode"
jwtExpirationMs: 86400000
jwtRefreshExpirationMs: 120000

Entity:

package com.backend.entity;

import com.backend.enums.ERole;
import jakarta.persistence.*;
import lombok.*;

import java.math.BigInteger;

@Entity
@Table(name = "roles")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 20, nullable = false)
    private ERole name;
}

Enum:

package com.backend.enums;

public enum ERole {
    USER,
    BUSINESS,
    ADMIN
}

Service:

package com.backend.services;


import com.backend.entity.Role;
import com.backend.enums.ERole;
import com.backend.repository.RoleRepository;

import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class RoleService {
    private final RoleRepository roleRepository;

    public RoleService(RoleRepository roleRepository) {
        this.roleRepository = roleRepository;
    }

    public Optional<Role> findByName(ERole name) {
        return roleRepository.findByName(name);
    }

}

Repository:

package com.backend.repository;

import com.backend.entity.Role;
import com.backend.enums.ERole;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
    Optional<Role> findByName(ERole name);
}

What I tried:

  1. Add @Autowired, and I get an error like this

  2. Add package scanning anotation to BackendApplication, and I get a similar error

I use gradlew:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.5'
    id 'io.spring.dependency-management' version '1.1.3'
    id 'org.asciidoctor.jvm.convert' version '3.3.2'
}

group = 'com.backend'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

ext {
    set('snippetsDir', file("build/generated-snippets"))
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
    implementation 'org.springframework.boot:spring-boot-starter-data-rest'
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'me.paulschwarz:spring-dotenv:4.0.0'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation:3.1.5'
    implementation 'org.mapstruct:mapstruct-processor:1.6.0.Beta1'
    implementation 'org.mapstruct:mapstruct:1.6.0.Beta1'
    implementation 'com.auth0:java-jwt:4.4.0'
    implementation 'io.jsonwebtoken:jjwt:0.12.3'
    implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
    implementation 'org.flywaydb:flyway-core'
    runtimeOnly 'org.flywaydb:flyway-mysql'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'com.mysql:mysql-connector-j'
    runtimeOnly 'io.asyncer:r2dbc-mysql'
    runtimeOnly 'io.r2dbc:r2dbc-h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'io.projectreactor:reactor-test'
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
    testImplementation 'org.springframework.security:spring-security-test'
}

tasks.named('test') {
    outputs.dir snippetsDir
    useJUnitPlatform()
}

tasks.named('asciidoctor') {
    inputs.dir snippetsDir
    dependsOn test
}

And Application file:

package com.backend;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

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

}

[SOLVED] I refactored gradlew, removed conflicting dependencies with DB:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.5'
    id 'io.spring.dependency-management' version '1.1.3'
}

group = 'com.backend'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web:3.1.5'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.1.5'
    implementation 'org.springframework.boot:spring-boot-starter-security:3.1.5'
    implementation 'org.springframework.boot:spring-boot-starter-validation:3.1.5'
    implementation 'com.mysql:mysql-connector-j:8.2.0'
    implementation 'com.auth0:java-jwt:4.4.0'
    implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
    implementation 'me.paulschwarz:spring-dotenv:4.0.0'
    implementation 'org.flywaydb:flyway-core:10.0.0'
    implementation 'org.flywaydb:flyway-mysql:10.0.0'
    compileOnly 'org.projectlombok:lombok:1.18.30'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'io.projectreactor:reactor-test'
}

tasks.named('test') {
    useJUnitPlatform()
}


Solution

  • Okay so the entire problem is that Spring is not able to decide how to create your Repository class, since you are having multiple starter-data projects implemented in your project. That is, you are using MySQL as your vendor, and for using an ORM with MySQL only JPA would suffice, but for any reasons like you want to write clear queries you may want to add JDBC as well, but removing R2DBC implementation and the unwanted Drivers from the dependencies cleared out your problem.

    dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-rest'
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'me.paulschwarz:spring-dotenv:4.0.0'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation:3.1.5'
    implementation 'org.mapstruct:mapstruct-processor:1.6.0.Beta1'
    implementation 'org.mapstruct:mapstruct:1.6.0.Beta1'
    implementation 'com.auth0:java-jwt:4.4.0'
    implementation 'io.jsonwebtoken:jjwt:0.12.3'
    implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
    implementation 'org.flywaydb:flyway-core'
    runtimeOnly 'org.flywaydb:flyway-mysql'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'io.projectreactor:reactor-test'
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
    testImplementation 'org.springframework.security:spring-security-test'}
    

    this will run your project

    and one more thing, I am not sure if Spring provides engine specific Dialects, but 5InnoDB Dialect is definitely not gonna work, you might want to implement an engine specific Driver then, else you could simply use MySQLDialect and your project would start running, without any problem.

    The issue was with Spring not knowing in which flavor it should create your repository class. And therefore left it uncreated, which later reflected in a bean not found exception.

    Hope you understood the problem.