SpringBoot JPA #Autowired no bean found exception - java

Edited to add proc structure:
main/java
hello(package)
Application(main app)
TestRestController
models(package)
Test
services(package)
TestRepo(interface)
I'm currently looking at component scan as just released the 'repo.Test' in the exception is a clue.
I've been through numerous tutorials and questions and still cannot find the answer to my particular issue, which is most likely to be down to my lack of understanding.
I have a spring boot application that I'm adding a db to. I've been following this tutorial : https://www.callicoder.com/spring-boot-rest-api-tutorial-with-mysql-jpa-hibernate/
However when I try and run my application (following identical steps) I get an exception:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testRestController': Unsatisfied dependency expressed through field 'testRepo'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'repo.TestRepo' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I do have another bean autowired in, the main difference is that this bean(the one that works) has a service that implements the interface and a bean configuration class. None of the examples for JPA follow that model and it seems daft to create a service to re-implement the methods from the JPARepo.
This is the controller I'm using:
#RestController
public class TestRestController {
#Autowired
GreetingService greetingService;
#Autowired
TestRepo testRepo;
#RequestMapping("/hello")
public String home() {
return greetingService.greet();
}
#RequestMapping("/testrepo")
public String testrepo() {
Test test = new Test("steve");
testRepo.save(test);
Long idOftest = test.getId();
test = null;
test = testRepo.findById(idOftest).get();
return "DID THIS WORK::::: + "+ test.toString();
}
with the interface being
#Repository
public interface TestRepo extends JpaRepository<Test, Long> {
}
and the model:
#Entity
#Data
public class Test {
private final String name;
public Test(String name){
this.name = name;
}
#Id
#GeneratedValue
private Long id;
public Long getId(){
return this.id;
}
}
The application main is:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
// #Bean
// public CommandLineRunner commandLineRunner(ApplicationContext ctx ) {
// return args -> {
//
// System.out.println("Let's inspect the beans provided by Spring Boot:");
//
// String[] beanNames = ctx.getBeanDefinitionNames();
// Arrays.sort(beanNames);
// for (String beanName : beanNames) {
// System.out.println(beanName);
// }
//
//
// };
// }
}
I recently commented out the bean annotation to see if that was causing an issue.
Thank you for any help in advance!

You are getting this exception because your class TestRepo is part of repo package, which is not the sub-package hierarchy of Application class package. #SpringBootApplication defines an automatic component scan on the packages which are subpackages of your main class i.e Application. If you want to resolve this issue without changing your package hierarchy add below line with #SpringBootApplication:
#ComponentScan({"repo","your.application.class.package"}) //// add the names of the packages where the controllers, services, repositories beans are stored

Related

Spring Boot unable to scan MongoRepository

I have a persistance interface that implements MongoRepository interface that looks as follows:
package org.prithvidiamond1.DB.Repositories;
import org.prithvidiamond1.DB.Models.SomeModel;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface ServerRepository extends MongoRepository<SomeModel, String> {
}
Despite this, I keep getting the following error:
Exception encountered during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'botApplication':
Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.prithvidiamond1.DB.Repositories.ServerRepository' available: expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations: {}
PPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in org.prithvidiamond1.BotApplication required a bean of type 'org.prithvidiamond1.DB.Repositories.ServerRepository' that could not be found.
Action:
Consider defining a bean of type 'org.prithvidiamond1.DB.Repositories.ServerRepository' in your configuration.
I have tried many solutions (custom #ComponentScan, using #Service instead of #Component, etc.) I found on the internet but none could help me solve the problem, can someone explain to me what is wrong and how I should fix this?
Note: The directory structure is as follows (this is not the full directory structure, but I think this should be enough to get an idea):
org.prithvidiamond1
|
+--BotApplication.java
|
+--DB
|
+--Repository
|
+--ServerRepository.java
BotApplication.java looks as follows:
package org.prithvidiamond1;
import org.jc.api.Api;
import org.jc.api.ApiBuilder;
import org.jc.api.entity.server.Server;
import org.prithvidiamond1.DB.Models.Server;
import org.prithvidiamond1.DB.Repositories.ServerRepository;
import org.slf4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.util.Collection;
#Component
public class BotApplication {
private final Api api;
private final ServerRepository serverRepository;
public BotApplication(ServerRepository serverRepository, Logger logger){
String botToken = System.getenv().get("BOT_TOKEN");
this.api = new ApiBuilder();
this.serverRepository = serverRepository;
appRuntime(logger);
}
public void appRuntime(Logger logger){
logger.info("Bot has started!");
// Handling server entries in the database
if (this.serverRepository.findAll().isEmpty()) {
logger.trace("server data repository empty, initializing data repository...");
Collection<Server> servers = api.getServers();
for (Server server : servers) {
this.serverRepository.save(new Server(String.valueOf(server.getId())));
}
logger.trace("server data repository initialized");
}
}
#Bean
public Api getApi() {
return this.api;
}
}
Edit: Here is a link to a repository with all the code: https://github.com/prithvidiamond1/DiamondBot/tree/springboot-restructure
The problem is that you are using the primary source class(BotApplication.class) for executing custom code during start-up.
public static void main(String[] args) {
ApplicationContext AppContext = SpringApplication.run(BotApplication.class, args);
}
public BotApplication(DiscordServerRepository serverRepository, Logger logger){
...
appRuntime(logger);
}
It is not a good place for using repositories or any startup code.
In the SpringApplication.run method you need to pass only classes which provide beans definitions. These are #Configuration classes.
See the best practices Running code after Spring Boot starts
I describe one of the best solutions: ApplicationRunner
BotApplication class must implement ApplicationRunner interface. The interface is used to indicate that a bean should run when it is contained within a SpringApplication.
Execute all startup code at the run method.
#Component
public class BotApplication implements ApplicationRunner {
private final DiscordApi api;
private final DiscordServerRepository serverRepository;
private final Logger logger;
public BotApplication(DiscordServerRepository serverRepository, Logger logger){
String botToken = System.getenv().get("BOT_TOKEN");
this.logger = logger;
this.serverRepository = serverRepository;
this.api = new DiscordApiBuilder()
.setToken(botToken)
.setAllIntents()
.setWaitForServersOnStartup(true)
.setWaitForUsersOnStartup(true)
.login().exceptionally(exception -> { // Error message for any failed actions from the above
logger.error("Error setting up DiscordApi instance!");
logger.error(exception.getMessage());
return null;
})
.join();
}
public void appRuntime(Logger logger){
logger.info("Bot has started!");
// Handling server entries in the database
if (this.serverRepository.findAll().isEmpty()) {
logger.trace("Bot server data repository empty, initializing data repository...");
Collection<Server> servers = api.getServers();
for (Server server : servers) {
this.serverRepository.save(new DiscordServer(String.valueOf(server.getId()), Main.defaultGuildPrefix));
}
logger.trace("Bot server data repository initialized");
}
}
#Bean
public DiscordApi getApi() {
return this.api;
}
#Override
public void run(ApplicationArguments args) throws Exception {
appRuntime(logger);
}
}
Pass Main.class to the SpringApplication.run
#SpringBootApplication
#EnableMongoRepositories
public class Main {
public static void main(String[] args) {
ApplicationContext AppContext = SpringApplication.run(Main.class, args);
}
}
use annotation #Autowired with the constructor of BotApplication class as shown below -
#Autowired
public BotApplication(ServerRepository serverRepository, Logger logger){
String botToken = System.getenv().get("BOT_TOKEN");
this.api = new ApiBuilder();
this.serverRepository = serverRepository;
appRuntime(logger);
}
You need to use #EnableMongoRepositories on top of your main application class to enable scanning of mongo repository beans.
You have Created Repository bean (ServerRepository)within your application.
But in your BotApplication component (which itself is a bean), you are not telling spring to inject dependency of Repository bean (i.e. Dependancy Injection).
Such a dependancy injection can be achieved by constructor , field-based or setter based methodologies.
You can either remove ServerRepository serverRepository from public BotApplication(ServerRepository serverRepository, Logger logger) constructor & just use :
#Autowired
private final ServerRepository serverRepository;
Or as other answer suggested, use #Autowired in Constructor itself and remove field ServerRepository serverRepository :
`
#Autowired
public BotApplication(ServerRepository serverRepository, Logger logger)
`
Please note, here, this.serverRepository = serverRepository; is also not required in constructor as dependency injection will take care of this.

Spring NoSuchBeanDefinitionException: No Qualifying Bean of Type [#Repository class] available

I see a lot of posts surrounding this error message, but none with a solution that's worked for me.
I'm writing a Spring application that has required me to configure multiple data sources. I got all of those working, but now I need to import a module my teammates built that uses an additional data source and several repositories. They've been using this module in their code and it seems to be working for them, but when I try to run my code I get the following error (some details obscured for work reasons):
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.company.teammodule.repositories.StatsRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
//I can't paste code, so there may be typos...
Spring Application Class:
package com.company.mymodule;
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan(basePackages={
"com.company.mymodule",
"com.company.mymodule.utils",
"com.company.mymodule.configuration",
"com.company.teammodule.repositories",
//I've been fiddling with packages here; I've added every package from the teammatemodule app and still get the error described})
#public class MyModuleApplication
{
public static void main(String[] args) { SpringApplication.run(MyModuleApplication.class, args); }
}
My class that uses the teammatemodule:
package com.company.mymodule.utils;
#Component
public class TeammateModuleUtil {
#Autowired
private TeammateModuleConfiguration config; //This class contains an object of another class which references the problem repository
#Value("${applicationName})
private final String applicationName;
public TeammateModuleUtil()
{
try {
config.setApplicationName(applicationName);
config.loadConfiguration();
}
catch (Exception e) {
//Error handling
}
}
}
The TeammateModuleConfiguration class:
package com.company.teammatemodule
#Component
public class TeammateModuleConfiguration extends ConfigurationBase {
#Autowired
TeammateModuleServiceData data; //This class contains a reference to the problem repository
#Autowired
Utilities util;
#Autowired
ConfigurationRepository configurationRepository;
public void loadConfiguration() throws Exception {
try {
this.alConfigure = this.configurationRepository.findByConfigureIdApplicationName(this.applicationName);
} catch (Exception e) {
//Error handling
}
}
}
Here's the class that has the problem reference:
package com.company.teammatemodule;
#Component
public class TeammateModuleServiceData {
#Autowired
StatsRepository statsRepository //This is the repo the code can't find a bean for
#Autowired
MessageAuthorizationRepository messageAuthorizationRepository;
#Autowired
LogMessagesRepository logMessagesRepository;
#Autowired
Utilities util;
//Class methods
}
And here's the repository class for good measure:
package com.company.teammatemodule.repositories;
#Repository
public interface StatsRepository extends JpaRepository<Stats, StatsId> {
#Procedure(
procedureName = "schema.log_service_stats",
outputParameterName = "o_stats_id"
)
String logServiceStats(#Param("i_request_payload") String var1, #Param("i_response_payload") String var2, #Param("i_operation_name") String var3, #Param("i_stats_id") String var4);
#Procedure(procedureName = "schema.update_service_stats)
void updateServiceStats(#Param("i_request_payload") String var1, #Param("i_response_payload") String var2, #Param("i_operation_name") String var3, #Param("i_stats_id) String var4);
}
The above repository is the one that can't be found when I try to launch the application. What I've checked and tried:
The main application has the #SpringApplication annotation, and all other involved classes have either #Component, #RestController, or #Repository, so I don't think it's an issue of some component not being labeled a bean...
None of the other repositories in teammatemodule are giving me a problem, but I'm guessing StatsRepository is just the first repository to be referenced
The only properties in my properties file are applicationName and data sources unrelated to the teammatemodule. I'm not listing any packages or exclusions there.
I've specified all packages in #ComponentScan ( basepackages = {//packages} ) as well as #SpringApplication( scanBasePackages = {//packages} )
I've tried excluding spring's autoconfigure by using the following annotations in my SpringAplication class:
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
So I don't think it's a missing #Component or other bean annotation, and to the best of my ability I've specified the package in which the repository bean is located and overridden Spring's built-in autoconfiguration tools... But the app still can't find the bean.
Thanks for your help!
It looks like this might just be a simple misspelling:
com.company.teammodule.repositories <- Component Scan
com.company.teammatemodule.repositories <- Package specified in Repository class

Ignore #Value field processing of dependent libraries from Spring Bean Post Processor

I am using one of our projects as a dependency in another. One of the classes in the dependent project is as follows:
#Service
public class Dependency {
#Value("${xyz.value}")
private String xyz;
#Value("${abc.value}")
private String abc;
public Dependency() {
}
public Dependency(String xyz, String abc) {
this.xyz = xyz;
this.abc = abc;
}
}
I am trying to create an instance of Dependency in another project on startup as follows:
#Configuration
#PropertySource(value = {
"classpath:appEnv.properties"
}, ignoreResourceNotFound = true)
public class Test {
#Bean(name = "dependencyBean")
public Dependent getDependent() {
return new Dependent("xyz", "abc");
}
}
Trying to access the dependencyBean created as follows
public class SomeClass {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Dependent d = ctx.getBean("dependencyBean");
}
I am getting the following exception
BeanCreationException: Error creating bean with name 'dependentBean': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.String xyz;
How can I create an instance of Dependent class without invoking postProcessPropertyValues which tries to resolve the fields with #Value annotation?
You, first, need to enable bean overriding with;
spring.main.allow-bean-definition-overriding=true
and just have your custom bean have the exact name as the #Service annotated class;
#Bean(name = "dependency")
public Dependency getDependent() {
return new Dependency("xyz", "abc");
}
Thus you can override the #Service annotated Dependency with your manually initialized bean. But to achieve that, you first have to disallow your custom getDependent() resulting bean to trigger #Value annotations, to do that, you need to change your Dependency class #Value injection method to constructor. When it is like that, only when Spring automatically injects, the #Value annotations will trigger, when you manually call new Dependency("xyz", "abc"), they won't.
#Service
public class Dependency {
private String xyz;
private String abc;
#Autowired
public Dependency(#Value("${xyz.value}") String xyz, #Value("${abc.value}") String abc) {
this.xyz = xyz;
this.abc = abc;
}
}
With these changes, you'll have no error with your custom bean autowired.

Getting NoSuchBeanDefinitionException while injecting bean dependency through constructor

I am trying to inject a configuration bean into my Service. For this i created a separate class EncryptionProps
public class EncryptionProps {
#Getter
#Setter
#Value("${kafka.properties.security.keyreuseinterval}")
private long keyReuseInterval;
}
Then, i am creating another config class to register this as a bean
#Configuration
public class EncryptionConfig {
#Bean
public EncryptionProps encryptionProps() {
return new EncryptionProps();
}}
And this is how, i am calling this in my service class:
#Service
public class EncryptionService {
private final long keyReuseInterval;
//some more declarations
#Autowired
public EncryptionService(SchemaProcessor schemaProcessor, CryptoLib crypto, EncryptionProps encryptionProps) {
this.schemaProcessor = Preconditions.checkNotNull(schemaProcessor, "schemaProcessor cannot be null.");
this.crypto = Preconditions.checkNotNull(crypto, "CryptoLib must be provided");
this.keyReuseInterval = encryptionProps.getKeyReuseInterval();
}
However, when i run this, i am getting the following error - org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.sinkad.kafka.util.EncryptionProps' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I am stuck on this since last day. I have tried tons of stackoverflow questions on this, but none helped so far. Can anybody please help me in why Spring is not finding this bean. I even tried adding #ComponentScan over the EncryptionConfig class. But that also didn't worked. Or if you can just point me to some resource related to it.
Thanks!
UPDATE:
Here is my main class:
package com.example.sinkad;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}}
Try like below:
#Component
class EncryptionProps {
final String keyreuseinterval;
// Use #Autowired to get #Value to work.
#Autowired
EncryptionProps(
#Value("${kafka.properties.security.keyreuseinterval}") final String keyreuseinterval) {
this.keyreuseinterval = keyreuseinterval;
}
}
I was finally able to solve this issue with a team member's help. I am still not sure what was the issue, But here's what we did:
1) Moved the keyReuseInterval value to another config class, which will create the object for EncryptionProps object
public class EncryptionProps {
#Getter
#Setter
private long keyReuseInterval;
}
Here 's the config class
#Configuration
public class CryptoConfig {
#Value("${kafka.properties.security.keyreuseinterval}")
private long keyReuseInterval;
#Bean
public EncryptionProps encryptionProps() {
EncryptionProps encryptionProps = new EncryptionProps();
encryptionProps.setKeyReuseInterval(keyReuseInterval);
return encryptionProps;
}
}
2) And we are calling encryptionProps in the service class similar to before:
#Autowired
public EncryptionService(SchemaProcessor schemaProcessor, CryptoLib crypto, EncryptionProps encryptionProps) {
this.schemaProcessor = Preconditions.checkNotNull(schemaProcessor, "schemaProcessor cannot be null.");
this.crypto = Preconditions.checkNotNull(crypto, "CryptoLib must be provided");
this.keyReuseInterval = encryptionProps.getKeyReuseInterval();
}
I am not sure how this fixed the issue. But thought will share it with you guys. Thanks again guys for your suggestions.

spring boot dependency injection

Im new to Spring, last couple of days I've been learning about it. Now Im trying to do something with it. It seems to me that with spring boot everything has changed.
There is no applicationContext file, I should use #Bean. Ok. In in tutorials the code is working, for me it fails. What did I miss?
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
the controller:
#RestController
public class GreetingController {
private final Test test;
#Autowired
public GreetingController(Test test){
this.test = test;
}
#RequestMapping("/greeting")
public String greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return "greeting" + test.getTest();
}
}
class Test {
public String getTest() {
return "tetst";
}
}
error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [hello.Test] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1301)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1047)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 18 more
I assume that bean has to be defined... But in tutorials there is no defenicion of bean.. Or I didnt see it.
Test class is not recognized as a Spring component. Therefore, you cannot inject it in your GreetingController. In order to inject Test object in that controller, annotate Test class with like #Component annotation (or with some other annotation that indicates that your class can be auto scanned).
Missed the full error. You need #Component on Test.

Categories

Resources