CRUD repository bean not found exception

2.2k views Asked by At

I have an application which connects to AWS DynamoDB. I am trying to implement Redis connection using Jedis into this application.

However, just after I add this dependency -

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

I get this error -

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

Description:

Field userInfoRepository in org.csulb.md.service.DBService required a bean of type 'org.csulb.md.repo.UserInfoRepository' 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 'org.csulb.md.repo.UserInfoRepository' in your configuration.

UserInfoRepository implements CrudRepository.

I am not sure what am I missing. In short, adding spring-boot-starter-data-redis dependency to this code gives this error. Without this dependency, code works fine.

Below is rest of my code.

MainApp.java

package org.csulb.md;

@SpringBootApplication
public class MainApp {

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

DynamoDBConfig.java

package org.csulb.md.config;

@Configuration
@EnableDynamoDBRepositories(basePackages = "org.csulb.md.repo")
public class DynamoDBConfig {
    
    @Value("${amazon.dynamodb.endpoint}")
    private String amazonDynamoDBEndpoint;
 
    @Value("${amazon.aws.accesskey}")
    private String amazonAWSAccessKey;
 
    @Value("${amazon.aws.secretkey}")
    private String amazonAWSSecretKey;
    
    @Value("${amazon.aws.awsSessionToken}")
    private String awsSessionToken;
 
    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        AmazonDynamoDB amazonDynamoDB 
          = new AmazonDynamoDBClient(amazonAWSCredentials());
        
        if (!StringUtils.isEmpty(this.amazonDynamoDBEndpoint)) {
            amazonDynamoDB.setEndpoint(this.amazonDynamoDBEndpoint);
        }
        
        return amazonDynamoDB;
    }
 
    @Bean
    public AWSCredentials amazonAWSCredentials() {
        
        AWSCredentials awsCredentials = null;
        
        if(StringUtils.isEmpty(this.awsSessionToken)) {
            awsCredentials = new BasicAWSCredentials(this.amazonAWSAccessKey, this.amazonAWSSecretKey);
        } else {
            awsCredentials = new BasicSessionCredentials(this.amazonAWSAccessKey, this.amazonAWSSecretKey, this.awsSessionToken);
        }
        
        return awsCredentials;
    }

UserInfoRepository.java

package org.csulb.md.repo;

@EnableScan
public interface UserInfoRepository extends CrudRepository<UserInfo, String> {}

GreetingController.java

package org.csulb.md.controller;

@RestController
public class GreetingController {
    
    @Autowired
    private DBService dbService;

    @GetMapping("/getdata")
    public UserInfo greeting(@RequestParam(value = "id") String id) {
        
        UserInfo userInfo = dbService.getUserById(id);
        return userInfo;
    }
}

UserInfo.java

package org.csulb.md.pojo;

@DynamoDBTable(tableName = "UserInfo")
public class UserInfo {
    
    @DynamoDBHashKey
    @DynamoDBAutoGeneratedKey
    @DynamoDBAttribute(attributeName = "id")
    private String id;
    
    @DynamoDBAttribute(attributeName = "name")
    private String name;
    
    @DynamoDBAttribute(attributeName = "location")
    private String location;

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
}

DBService.java

package org.csulb.md.service;

@Component
public class DBService {
    
    Logger logger = LoggerFactory.getLogger(DBService.class);
    
    @Autowired
    private UserInfoRepository userInfoRepository;
    
    public UserInfo getUserById(String id){
        
        Optional<UserInfo> userId = userInfoRepository.findById(id);
        UserInfo userInfo = new UserInfo();
        
        if(userId.isPresent()) {
            logger.info("UserInfo found: "+userId.get().getId());
            BeanUtils.copyProperties(userId.get(), userInfo);
        } else {
            logger.info("UserInfo not found: "+id);
        }
        
        return userInfo;
    }

}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath />
    </parent>

    <groupId>org.csulb.md</groupId>
    <artifactId>dynamodb-connector</artifactId>
    <version>0.0.1</version>
    <name>dynamodb-connector</name>

    <properties>
        <java.version>1.8</java.version>
        <docker.image.prefix>springio</docker.image.prefix>
        <start-class>org.csulb.md.MainApp</start-class>
    </properties>

    <dependencies>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-dynamodb</artifactId>
            <version>1.11.64</version>
        </dependency>

        <dependency>
            <groupId>com.github.derjust</groupId>
            <artifactId>spring-data-dynamodb</artifactId>
            <version>5.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

P.S - Adding @ComponentScan("org.csulb.md.repo") to main class solves this error, but it fails to recognize other components hence controller fails to work. I tried adding @ComponentScan("org.csulb.md) as well which gives same error as described. I tried adding @Repository/@Component on UserInfoRepository & found no luck.

1

There are 1 answers

3
Anmol Bhatia On BEST ANSWER

I had the same issue which happened when i tried to use spring-data-dynamodb and spring data-redis. The issue is happening because of implementation gap in spring-data-dynamodb. It doesn't support multiple data store setup. You can find the same in the logs for this as well: Spring Data DynamoDB does not support multi-store setups!.

Coming to the solution, with using multiple data stores, Spring data enters into strict mode of repository scanning. So in my case i was able to add includeFilters in @EnableDynamoDBRepositories. Add this to enable strict repository scanning:

@EnableDynamoDBRepositories(basePackages = "org.csulb.md.repo",
        includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Repository.class))

Add org.springframework.stereotype.Repository annotation to UserInfoRepository.java class.