Can't Autowire #Repository annotated interface in Spring Boot - spring

I'm developing a spring boot application and I'm running into an issue here. I'm trying to inject a #Repository annotated interface and it doesn't seem to work at all. I'm getting this error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springBootRunner': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.pharmacy.persistence.users.dao.UserEntityDao com.pharmacy.config.SpringBootRunner.userEntityDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.pharmacy.persistence.users.dao.UserEntityDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1202)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at com.pharmacy.config.SpringBootRunner.main(SpringBootRunner.java:25)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.pharmacy.persistence.users.dao.UserEntityDao com.pharmacy.config.SpringBootRunner.userEntityDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.pharmacy.persistence.users.dao.UserEntityDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 16 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.pharmacy.persistence.users.dao.UserEntityDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
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.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
... 18 common frames omitted
Here is my code:
Main application class:
package com.pharmacy.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan("org.pharmacy")
public class SpringBootRunner {
public static void main(String[] args) {
SpringApplication.run(SpringBootRunner.class, args);
}
}
Entity class:
package com.pharmacy.persistence.users;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class UserEntity {
#Id
#GeneratedValue
private Long id;
#Column
private String name;
}
Repository interface:
package com.pharmacy.persistence.users.dao;
import com.pharmacy.persistence.users.UserEntity;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserEntityDao extends CrudRepository<UserEntity,Long>{
}
Controller:
package com.pharmacy.controllers;
import com.pharmacy.persistence.users.UserEntity;
import com.pharmacy.persistence.users.dao.UserEntityDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HomeController {
#Autowired
UserEntityDao userEntityDao;
#RequestMapping(value = "/")
public String hello() {
userEntityDao.save(new UserEntity("ac"));
return "Test";
}
}
build.gradle
buildscript {
ext {
springBootVersion = '1.2.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'spring-boot'
mainClassName = "com.pharmacy.config.SpringBootRunner"
jar {
baseName = 'demo'
version = '0.0.1-SNAPSHOT'
}
repositories {
mavenCentral()
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-ws")
compile("postgresql:postgresql:9.0-801.jdbc4")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
application.properties:
spring.view.prefix: /
spring.view.suffix: .html
spring.jpa.database=POSTGRESQL
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=update
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=abc123
I even compared my code with Accessing data jpa, and I'm running out of ideas what's wrong with this code.
Any help appreciated.
EDITED: I changed my code as suggested to look like above, and I'm not getting that error when I'm injecting my #Repository interface into another component. However, I have a problem now - my component cannot be retrieved (I used debugging). What I'm doing wrong so spring cannot find my component?

When the repository package is different to #SpringBootApplication/#EnableAutoConfiguration, base package of #EnableJpaRepositories is required to be defined explicitly.
Try to add #EnableJpaRepositories("com.pharmacy.persistence.users.dao") to SpringBootRunner

I had the same issues with Repository not being found. So what I did was to move everything into 1 package. And this worked meaning that there was nothing wrong with my code. I moved the Repos & Entities into another package and added the following to SpringApplication class.
#EnableJpaRepositories("com...jpa")
#EntityScan("com...jpa")
After that, I moved the Service (interface & implementation) to another package and added the following to SpringApplication class.
#ComponentScan("com...service")
This solved my issues.

There is another cause for this type of problem what I would like to share, because I struggle in this problem for some time and I could't find any answer on SO.
In a repository like:
#Repository
public interface UserEntityDao extends CrudRepository<UserEntity, Long>{
}
If your entity UserEntity does not have the #Entity annotation on the class, you will have the same error.
This error is confusing for this case, because you focus on trying to resolve the problem about Spring not found the Repository but the problem is the entity. And if you came to this answer trying to test your Repository, this answer may help you.

It seems your #ComponentScan annotation is not set properly.
Try :
#ComponentScan(basePackages = {"com.pharmacy"})
Actually you do not need the component scan if you have your main class at the top of the structure, for example directly under com.pharmacy package.
Also, you don't need both
#SpringBootApplication
#EnableAutoConfiguration
The #SpringBootApplication annotation includes #EnableAutoConfiguration by default.

I had a similar issue where I was receiving NoSuchBeanDefinitionException in Spring Boot (basically while working on CRUD repository), I had to put the below annotations on the main class:
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan(basePackages={"<base package name>"})
#EnableJpaRepositories(basePackages="<repository package name>")
#EnableTransactionManagement
#EntityScan(basePackages="<entity package name>")
Also, make sure you have the #Component annotations in place on the implementations.

In SpringBoot, the JpaRepository are not auto-enabled by default. You have to explicitly add
#EnableJpaRepositories("packages")
#EntityScan("packages")

#SpringBootApplication(scanBasePackages=,<youur package name>)
#EnableJpaRepositories(<you jpa repo package>)
#EntityScan(<your entity package>)
Entity class like below
#Entity
#Table(name="USER")
public class User {
#Id
#GeneratedValue

To extend onto above answers, You can actually add more than one package in your EnableJPARepositories tag, so that you won't run into "Object not mapped" error after only specifying the repository package.
#SpringBootApplication
#EnableJpaRepositories(basePackages = {"com.test.model", "com.test.repository"})
public class SpringBootApplication{
}

It could be to do with the package you have it in. I had a similar problem:
Description:
Field userRepo in com.App.AppApplication required a bean of type 'repository.UserRepository' 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 'repository.UserRepository' in your configuration.
"
Solved it by put the repository files into a package with standardised naming convention:
e.g. com.app.Todo (for main domain files)
and
com.app.Todo.repository (for repository files)
That way, spring knows where to go looking for the repositories, else things get confusing really fast. :)
Hope this helps.

You are scanning the wrong package:
#ComponentScan("**org**.pharmacy")
Where as it should be:
#ComponentScan("**com**.pharmacy")
Since your package names start with com and not org.

I had some problems with this topic too.
You have to make sure you define the packages in Spring boot runner class like this example below:
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan({"controller", "service"})
#EntityScan("entity")
#EnableJpaRepositories("repository")
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
I hope this helps!

Here is the mistake: as someone said before, you are using org.pharmacy insted of com.pharmacy in componentscan
package **com**.pharmacy.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan("**org**.pharmacy")
public class SpringBootRunner {

If you're facing this problem when unit testing with #DataJpaTest then you'll find the solution below.
Spring boot do not initialize #Repository beans for #DataJpaTest. So try one of the two fix below to have them available:
First
Use #SpringBootTest instead. But this will boot up the whole application context.
Second(Better solutions)
Import the specific repository you need, like below
#DataJpaTest
#Import(MyRepository.class)
public class MyRepositoryTest {
#Autowired
private MyRepository myRepository;

I had a similar issue with Spring Data MongoDB: I had to add the package path to #EnableMongoRepositories

I resolved that issue by changing that dependency :
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
With that one :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
In that way there is no need to use Anotations like :
#EnableAutoConfiguration
#ComponentScan({"controller", "service"})
#EntityScan("entity")
#EnableJpaRepositories("repository")
)

I had a similar problem but with a different cause:
In my case the problem was that in the interface defining the repository
public interface ItemRepository extends Repository {..}
I was omitting the types of the template. Setting them right:
public interface ItemRepository extends Repository<Item,Long> {..}
did the trick.

In #ComponentScan("org.pharmacy"), you are declaring org.pharmacy package.
But your components in com.pharmacy package.

Many of the answer up there help a lot, because they are part of the whole solution. For me it was a mix of some of them.
Your ComponentScan package is wrong. Change it to:
#ComponentScan("com.pharmacy")
You also have to add:
#EnableJpaRepositories
to your SpringBootApplication class, here: SpringBootRunner.
I had to change the Maven dependency (works similarly for Gradle):
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
To:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Don't forget to refresh your dependencies.
Then I also had to change my imports in my Entity class to:
import jakarta.persistence.*;

Make sure the #Service or #Component that is trying to auto-wire the repository isn't in the same directory as your SpringApplication.class. Make sure it's in a subfolder like service/.

Sometimes I had the same issues when I forget to add Lombok annotation processor dependency to the maven configuration

Adding the below dependency on pom.xml solved the problem
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

If your main class is in com.example package your other class should which are in different packages should be called in com.example package;
i.e:Controller package
com.example.controller
AND
Your Main class should be in com.example not in com.example.main
if you gave the main class package as com.example.main then the other should be within that package e.g com.package.main.controller

Related

JUnit #DataJpaTest org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name

I'm trying to do a test on the repository using #DataJPATest but #Autowired is not working
I already tried looking for examples of junit5 with #DataJpaTest, but I didn't find it
I tried adding other dependencies, I used #SpringTest and it worked, but I wanted to use #DataJpaTest
package com.projetoSpring.catalog.repositories;
import com.projetoSpring.catalog.model.Product;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import java.util.Optional;
#DataJpaTest
public class ProductRepositoryTests {
#Autowired
private ProductRepository repositorys;
#Test
public void deleteShouldDeleteObjectWhenIdExists() {
long exintingId = 1L;
repositorys.deleteById(exintingId);
Optional<Product> result = repositorys.findById(1L);
Assertions.assertFalse(result.isPresent());
}
}
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.projetoSpring.catalog.repositories.ProductRepositoryTests': Unsatisfied dependency expressed through field 'repositorys'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.projetoSpring.catalog.repositories.ProductRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I managed to solve it, I updated spring to version 2.7.5 and I verified that the test dependency was not downloading correctly, I redid the pom.xml and it worked.

Why #MockBean ConversionService causes an error

Given: JUnit 5 and empty SpringBoot project created with Intellij IDEA Ultimate. I get the same results for projects with a controller that contains #Autowired ConversionService.
I need to use in a test the mocked version of ConversionService.
This is my approach:
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.convert.ConversionService;
#SpringBootTest
public class ConversionServiceTest {
#MockBean
ConversionService conversionService;
#Test
void test() {}
}
The above code causes the error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.format.support.FormattingConversionService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Qualifier(value="mvcConversionService")}
What is the reason for this error and what is the solution?
The solution is to replace #MockBean by #SpyBean.

Spring #Service defined in Kotlin file results in 'UnsatisfiedDependencyException: Error creating bean' when referenced

I have an existing Springboot/Java application and I wanted to start migrating the application to Kotlin. I create a #Service in Kotlin, and my unit test fails at runtime because Spring can't find my service.
My unit test:
#ExtendWith(SpringExtension::class)
#SpringBootTest(classes = arrayOf(Application::class))
class Junit5SpringKotlinTests {
#Autowired // Springboot ConfigurationProperties (application.yaml) mapped to Java bean. This works.
lateinit var applicationConfigurationJavaBean: EnvironmentProperties
fun appProperties(): EnvironmentProperties.Environment? {
return applicationConfigurationJavaBean.environments[applicationConfigurationJavaBean.activeEnvironment]
}
#Autowired
lateinit var testServiceKotlinBean :TestService // My Kotlin #Service which can not be found at runtime.
#Test
fun `ApplicationConfiguration`() {
println(appProperties()?.baseClientId)
testServiceKotlinBean.hello()
}
}
My Kotlin service: TestService.kt
import org.springframework.stereotype.Service
#Service
class TestService {
fun hello() {
println("hello from service")
}
}
My error at runtime executing the unit test:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'Junit5SpringKotlinTests': Unsatisfied dependency expressed through field 'testServiceKotlinBean'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'api.model.TestService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'api.model.TestService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1509)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
FWW, I am able to write JUnit5 SpringBootTests in Kotlin test code and exercise all my Java components, so this has something to do with Kotlin components being discovered at runtime by Spring. Java components work.
I suspected this might be a build problem and have seen similar issues. I have the following included in my pom.xml:
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
</dependency>
so that wasn't the problem.
The problem was the package name I used for the Kotlin service. Kotlin is nice in that I don't have put my files in the same package path like java. But my Spring classpath scanning was relying on a package: A.B.C and below and my Kotlin path only had C. I changed the package name in my Kotlin file to be A.B.C.TestService and all is fine. Yay.

Spring JPA not implementing/autowiring repository despite #EnableJpaRepositories annotation

I'm getting an exception when I start my application, where Spring complain about UnsatisfiedDependencyException:
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'applicationConfig': Unsatisfied dependency expressed through field 'controlRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean found for dependency [com.oak.api.finance.repository.ControlRepository]: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:569)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
My application is organized in this format:
I declared my repository interfaces, with the proper Spring JPA annotations:
#RepositoryRestResource(collectionResourceRel = "exchange", path = "exchanges")
public interface ControlRepository extends PagingAndSortingRepository<Control, Long> {
}
I annotated the EntryPoint class that contains the main method
#SpringBootApplication
#EntityScan(basePackages = {"com.oak.api.finance.model.dto"})
#EnableJpaRepositories(basePackages = {"com.oak.api.finance.repository"})
public class EntryPoint {
public static void main(String[] args) {
Logger logger = LogManager.getLogger(EntryPoint.class);
logger.info("Starting application");
ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class);
// SpringApplication.run(EntryPoint.class, args);
ctx.getBean(ApplicationServer.class).start();
}
I used #Autowired to inject my repository into my spring config (java based) ApplicationConfig class:
#Autowired
private ControlRepository controlRepository;
#Autowired
private CompanyRepository companyRepository;
#Autowired
private SectorRepository sectorRepository;
Essentially I want to control the dependency on Spring and limit it to a couple of packages, (the repositories, the java config, and the program entry point - EntryPoint)
I assumed that, by specifying #EnableJpaRepositories with the package where my repositories are located, spring would create a proxy for my repository and instantiate an instance of that, and that by the time I call :
ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class)
The repositories instances would be present in the beans poole and would be possible to autowire them into my ApplicationConfig context, and then inject them into my controller.
This is clearly not happening, and Spring is complaining about the missing Bean to autowire, but I'm not sure what am I missing.
Below a snapshot of my packages:
any ideas?
My guess is your repositories are not being scanned, so as a result beans are not getting created. Can you try removing these 2 annotations
#EntityScan(basePackages = {"com.oak.api.finance.model.dto"})
#EnableJpaRepositories(basePackages = {"com.oak.api.finance.repository"})
And keep only #SpringBootApplication. If this is not working, you might need to check the package structure (if possible paste a screenshot here)
Edit 1
replace #SpringBootApplication with
#Configuration
#EnableAutoConfiguration
#ComponentScan("com.oak")
Edit2
Use
new SpringApplicationBuilder()
.sources(SpringBootApp.class)
.web(false)
.run(args);
Or use CommandLineRunner after changing ComponentScan path to "com.oak" as mh-dev suggested

spring boot repository metrics

I am trying to make an object repositoryMetrics in SpringBoot and later I obtained information with this repository. But I create a repository and this always is null.
How I generate a repository and this save the metrics?
I have this code:
public static void stateSist() throws Exception {
InMemoryMetricRepository metricRepository = null;
metricRepository.findAll();
System.out.println(metricRepository.count());
}
EDIT 1:
I do this change in my version and I obtained this error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'actuatorMetricsPrinter' defined in file [ActuatorMetricsPrinter.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.util.Collection]: : No qualifying bean of type [org.springframework.boot.actuate.endpoint.PublicMetrics] found for dependency [collection of org.springframework.boot.actuate.endpoint.PublicMetrics]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.boot.actuate.endpoint.PublicMetrics] found for dependency [collection of org.springframework.boot.actuate.endpoint.PublicMetrics]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1115)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at hello.Application.main(Application.java:14)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.boot.actuate.endpoint.PublicMetrics] found for dependency [collection of org.springframework.boot.actuate.endpoint.PublicMetrics]: 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:1118)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:919)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)
... 18 common frames omitted
Thank you!
In order to access all Public Metrics printed by the Spring Boot actuator framework you need to inject a 'Collection' into your component and then access it to read all the metrics. Here is an example:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.PublicMetrics;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.stereotype.Component;
import java.util.Collection;
#Component
public class ActuatorMetricsPrinter {
private static final String TEMPLATE = "Metric: %s [%s]";
private final Collection<PublicMetrics> publicMetrics;
#Autowired
public ActuatorMetricsPrinter(Collection<PublicMetrics> publicMetrics) {
this.publicMetrics = publicMetrics;
}
public String printAllMetrics() {
StringBuilder sb = new StringBuilder();
for (PublicMetrics pm : publicMetrics) {
sb.append("Public Metric: " + pm.getClass().getName());
sb.append("\n\n");
for (Metric<?> m : pm.metrics()) {
sb.append(String.format(TEMPLATE, m.getName(), m.getValue().toString()));
sb.append("\n");
}
}
return sb.toString();
}
}
If you want to reproduce this simple scenario, then:
Go to http://start.spring.io/ and create new project with Actuator and Web checked,
Create a demo project with Build tool of your choice (Gradle, Maven),
Download it and open in your IDE,
Create a new component just like one in my example,
Create a new RestController, like this:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class DummyController {
private final ActuatorMetricsPrinter metricsPrinter;
#Autowired
public DummyController(ActuatorMetricsPrinter metricsPrinter) {
this.metricsPrinter = metricsPrinter;
}
#RequestMapping(value = "/customMetrics", method = RequestMethod.GET)
public String printMetrics() {
return metricsPrinter.printAllMetrics();
}
}
Then start the application and type in your browser: http://localhost:8080/customMetrics
You should see all the metrics printed by your class in the most messy way possible
If you are using Maven or Gradle for dependency management, then you must make sure these are present in either (from Spring Clouds's Home Page):
Maven:
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Angel.SR4</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
Gradle:
buildscript {
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:0.4.0.RELEASE"
}
}
apply plugin: "io.spring.dependency-management"
dependencyManagement {
imports {
mavenBom 'org.springframework.cloud:spring-cloud-starter-parent:Angel.SR4'
}
}
dependencies {
compile 'org.springframework.cloud:spring-cloud-starter-config'
compile 'org.springframework.cloud:spring-cloud-starter-eureka'
}
If you omit the parent in Maven or the dependencyManagement in gradle, and try to just import the latest version of each of the dependencies, you will get the runtime error that you are describing.
A similar problem addresses this here on GitHub.

Resources