Springboot application throws a NoSuchBeanDefinitionException trying to Autowire CouchbaseCluster [duplicate] - java

This question already has an answer here:
What is a NoSuchBeanDefinitionException and how do I fix it?
(1 answer)
Closed 2 years ago.
I work with a legacy springboot application which has a huge com.mycompany.MyApplication class where there are injected a bunch of spring objects through #Autowire annotation.
Trying to split MyApplication class up, I created several classes and put them in different packages but I got an issue with CouchbaseCluster autowire injection; the error is:
AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myApplication': Unsatisfied dependency expressed through field 'step'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jobSteps': Unsatisfied dependency expressed through field 'couchbaseFlushCacheTasklet'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'couchbaseFlushCacheTasklet': Unsatisfied dependency expressed through field 'cluster'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.couchbase.client.java.CouchbaseCluster' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
***************************
APPLICATION FAILED TO START
***************************
Description:
Field cluster in com.mycompany.batch.tasklet.CouchbaseFlushCacheTasklet required a bean of type 'com.couchbase.client.java.CouchbaseCluster' 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.couchbase.client.java.CouchbaseCluster' in your configuration.
Here is an example of my code:
package com.mycompany;
#EnableBatchProcessing
#SpringBootApplication
public class MyApplication implements CommandLineRunner {
#Autowired
JobSteps step;
...
}
package com.mycompany.batch;
#Configuration
public class JobSteps {
#Autowired
CouchbaseFlushCacheTasklet couchbaseFlushCacheTasklet;
#Autowired
CouchbaseDeleteNonBatchTasklet couchbaseDeleteNonBatchTasklet;
...
}
If you note in the next code snipped, cluster uses the #SuppressWarnings annotation because Intellij marks this with this error: 'Could not autowire. No beans of 'CouchbaseCluster' type found.' however it was before and after my changes, but before the application ran without issues.
package com.mycompany.batch.tasklet;
#Component
public class CouchbaseFlushCacheTasklet {
#SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
#Autowired
CouchbaseCluster cluster;
...
}
I am putting this next class to show that there is any problem with the bean Budget, which is located in the same library/package than CouchbaseCluster com.couchbase.client.java.Bucket
package com.mycompany.batch.tasklet;
#Component
public class CouchbaseDeleteNonBatchTasklet {
#Autowired
Bucket bucket;
...
}
POM dependencies associated with couchbase
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>3.1.9.RELEASE</version>
</dependency>
I tried to specify the scanBasePackeges but didn't work.
#SpringBootApplication(scanBasePackages = {"com.mycompany", "com.couchbase.client"})
Any clue will be appreciated since I have spent a lot of time looking for a solution and so far none of the suggested things in similar posts have worked.
I solved it :-)
Instead of autowire this
#Autowired
CouchbaseCluster cluster;
I autowire this
#Autowired
Cluster cluster;
I am not sure how was possible that at some point it worked autowiring CouchbaseCluster

First thing CouchbaseCluster class should be part of the bean life cycle, it should be annotated with an annotation like #Component etc. if so you must check you should not be creating the object of any class using the new keyword.
So in your case, it will be resolved something like this. add the below method into JobSteps.
#Bean
public CouchbaseCluster couchbaseCluster(){
CouchbaseEnvironment env = DefaultCouchbaseEnvironment.builder()
.bootstrapCarrierDirectPort(couchbase.getMappedPort(11210))
.bootstrapCarrierSslPort(couchbase.getMappedPort(11207))
.bootstrapHttpDirectPort(couchbase.getMappedPort(8091))
.bootstrapHttpSslPort(couchbase.getMappedPort(18091))
.build();
CouchbaseCluster cc = CouchbaseCluster.create(env);
return cc;
}
Modified the CouchbaseEnvironment object according to your configuration.

Have you tried creating your Cluster in the #PostConstruct?
#Service
public class CouchbaseFlushCacheTasklet {
private Cluster cluster;
#PostConstruct
private void init() {
CouchbaseEnvironment env = DefaultCouchbaseEnvironment.create();
cluster = CouchbaseCluster.create(env, "localhost");
}
...
}
Code from: https://www.baeldung.com/couchbase-sdk-spring
Alternatively, try adding an #Bean producer somewhere instead of using a #PostConstruct.

Related

While taking Bean out of ApplicationContext, there was an error that the MemberRepository did not have an error occurred

I want to declare ApplicationContext and take out Bean using getBean.
But I got this error.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'inactiveMemberJobConfig': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.capston.chatting.repository.MemberRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.capston.chatting.repository.MemberRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I expect that I have already used #Repository to register the MemberRepository as an bean
However, the error log shows that there is no MemberRepository.
I don't understant where is wrong
Below is my code.
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(InactiveMemberJobConfig.class);
Job inactiveMemberJob = (Job) ac.getBean("inactiveMemberJob");
#Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
#Query("select m from Member m where m.loginId = :loginId")
Member findMemberByLoginId(#Param("loginId") String loginId);
List<Member> findByUpdateDateBeforeAndStatusEquals(LocalDateTime localDateTime, MemberStatus status);
}
#Slf4j
#RequiredArgsConstructor
#Configuration
public class InactiveMemberJobConfig {
private final MemberRepository memberRepository;
//...
}
For a bean to be known to an application context it needs to be registered. That can happen e.g. through component scanning which detects the annotation on the class and registers it as a bean.
When you do new AnnotationConfigApplicationContext() you created a new application context. This application context did not do any component scanning yet. Furthermore, within this constructor it tries to find the bean dependencies of the class you pass as constructor parameter. But since no component scanning has taking place yet it cannot find it.
You need to create your application context with a class that has no bean dependencies yet. And then register your beans, e.g. through executing the component scan on you application context.
See example below:
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);
ac.scan(MyConfig.class.getPackageName());
InactiveMemberJobConfig inactiveMemberJob = (InactiveMemberJobConfig) ac.getBean(InactiveMemberJobConfig.class);
I hope this helps.

No qualifying bean of type 'javax.persistence.EntityManager' available when import jar dependency

I'm working on two relative projects. One project is used to connect to postgresql and another project import the connector project as dependency to connect to postgresql. In connector project I used EntityManager to access to database.
In Repository class I use entity manager to get entity
#Transactional
#Repository
public class ConfigDetailRepository {
private EntityManager entityManager;
#Autowired
public ConfigDetailRepository(final EntityManager entityManager) {
this.entityManager = entityManager;
}
public void doSomething()
And in Service class I autowire repository
#Configurable
#Service
public class SampleService {
#Autowired
private ConfigDetailRepository configDetailRepository;
public class (){ configDetailRepository.doSomething()}
This connector project is workable and able to get data from database. In my second project I import the connector project and add this dependency in pom.xml
<dependency>
<groupId>package name</groupId>
<artifactId>package-id</artifactId>
<version>package-version</version>
</dependency>
And that's my Application.class and class import SampleService
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
#ComponentScan(basePackages = {"package name"})
public class CassandraTestApplication {
public static void main(String[] args) {
SpringApplication.run(CassandraTestApplication.class, args);
}
#Configurable
#Component
public class TestConnector {
#Autowired
SampleService sampleService;
public void doSomtehing() {
sampleService.doSomething();
}
}
When I run the project I got following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in package.repository.ConfigDetailRepository required a bean of type 'javax.persistence.EntityManager' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testConnector': Unsatisfied dependency expressed through field 'sampleService'; nested exception is org.springframework.beans
.factory.UnsatisfiedDependencyException: Error creating bean with name 'sampleService': Unsatisfied dependency expressed through field 'configDetailRepository'; nested exception is org.springframework.beans.factory.UnsatisfiedDepende
ncyException: Error creating bean with name 'configDetailRepository' defined in URL [jar:file:/C:/Users/.m2/repository/com/connector/cassandra-db/0.0.1-SNAPSHOT/cassandra-db-0.0.1-SNAPSHOT.jar!/com/repository/ConfigDetailRepository.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying b
ean of type 'javax.persistence.EntityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I check the connector project and it can work. Then I tried exclude=HibernateJpaAutoConfiguration.class but that didn't work. Can anyone tell me why the entity manager cannot be created?
The problem is the exclude = {DataSourceAutoConfiguration.class}. With this you are excluding the configuration of the DataSource by Spring Boot. Unless you specify one yourself using an #Bean method this basically prevents you from doing all DB related work.
JPA requires access to your database and without a configured DataSource this will not be possible. Due to the missing DataSource Spring Boot will also not configure JPA. No JPA will lead to this error.
To fix, remove the exclude and provide the configuration for the database.

Unsatisfied dependency expressed through field 'fooService': No qualifying bean of type [aaa.FooService] found for dependency [aaa.FooService]

I have encountered this weird behavior of Spring in Spring boot 1.4.0. Spring basically tells me that it cannot autowire a bean to the resource, because it did not found itself for dependency.
UnsatisfiedDependencyException: Error creating bean with name 'restResource': Unsatisfied dependency expressed through field
'fooService': No qualifying bean of type [**aaa.FooService**] found for dependency [**aaa.FooService**]
FooService is autowired in the resource. When I #Autowire it into #Configuration file, which creates the resource, it is injected there as expected.
This works:
public class ServiceMocksRestConfig extends WebMvcConfigurerAdapter {
#Autowired
private FooService fooService; //instance here
#Bean
public FooResource fooResource() {
return new FooResource(); // debuger stop here
}
//Debugger step into
#RestController
public class FooResource {
#Autowired
private FooService fooService; //bang
Does someone has any idea, what might went wrong?
Funny stuff is that when I run the app from tests using boot spring runner, it also works (everything, including this resource)
I managed today to find the root cause. Its Spring Boot devtools - more precisely its split classloader (related bug: https://github.com/spring-projects/spring-boot/issues/3316)
When I put a breakpoint in ListableBeanFactory when the child REST #Configuration was about to #Autowire the FooService
and did FooService instanceof FooServiceInterface, it returned false.
And when I did FooService.class.getClassLoader() and beanfactory.getBean("fooService" /cannot use class here, would trigger not found exception/).getClass().getClassloader() these were different (one was AppClassLoader and the other was devtools restartable class loader).
Solution: remove boot devtools from classpath.
The exact reason for this is that, there is no bean initialized for type FooService inside the Spring IOC container at the moment the run-time tries to autowire FooService into ServiceMocksRestConfig .
It can be cause by different mistakes in development. This article addresses each and every possible mistakes that can cause this problem.

Autowiring Embedded Elastic with Spring

I'm trying to build a rest api with Spring and Embedded Elastic. I'm getting an NoSuchBeanDefinitionException when trying to start my application.
Currently, I have this for wiring the elastic db:
#Configuration
public class EsConfig {
Node node;
#Bean
public Client es() {
node = nodeBuilder().local(true).node();
return node.client();
}
(Destructor)
}
and in the controller:
#RestController
public class Controller {
#Autowired
public Client elasticSearchClient;
...
}
But when I start it up, I get this exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'controller': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: public org.elasticsearch.client.Client package.Controller.elasticSearchClient;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [org.elasticsearch.client.Client] 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)}
I've tried a few different annotations but I'm obviously way off.
No qualifying bean of type [some.Thing] means that spring knowns no class that is applicable for this interface.
Reasons for that can be
The class that has the #Bean method is not a #Configuration class
The #Configuration class is not picked up by the classpath component scanner.
Spring boot by default will only scan the child package hierarchy of the #SpringBootApplication. If you want to include code outside of that you can change the scanning behavior via the #ComponentScan annotation.
#SpringBootApplication
#ComponentScan(basePackageClasses = {MyApp.class, SomeOtherClassInARootPackage.class})
public class MyApp {
...
Would add the package (and sub packages) of some other class, while keeping the packages of the application scanned as well.

How to Autowired in ConversionService in springboot

Trying to access the ConversionControl in model in springboot, no luck.
#Component
public class CityHelperService {
#Autowired
ConversionService conversionService;// = ConversionServiceFactory.registerConverters();
public City toEntity(CityDTO dto){
City entity = conversionService.convert(dto, City.class);
return entity;
}
public CityDTO toDTO(City entity){
CityDTO dto = conversionService.convert(entity, CityDTO.class);
return dto;
}
}
It shows the following error:
Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.lumiin.mytalk.model.CityModel com.lumiin.mytalk.controllers.CityController.cityModel;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cityModel' defined in file : Unsatisfied dependency expressed through constructor argument with index 1 of type [com.lumiin.mytalk.dao.CityHelperService]: : Error creating bean with name 'cityHelperService': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.core.convert.ConversionService com.lumiin.mytalk.dao.CityHelperService.conversionService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] 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)};
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cityHelperService': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.core.convert.ConversionService com.lumiin.mytalk.dao.CityHelperService.conversionService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] 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)}
Apparently there is no ConversionService bean available, judging by the last nested exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
A look into the Spring documentation reveals, that you should declare a ConversionService bean. In the XML configuration it would look like this:
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="example.MyCustomConverter"/>
</set>
</property>
</bean>
And since you're using Spring Boot, I assume you are creating the context programatically, so you should create a method annotated with #Bean, which returns a ConverstionService, like this (explained here):
#Bean(name="conversionService")
public ConversionService getConversionService() {
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
bean.setConverters(...); //add converters
bean.afterPropertiesSet();
return bean.getObject();
}
Not totally agreed with the accepted answers, because there would be a default ConverstionService named mvcConversionService so you would get duplicate bean exception. Instead addConverter to FormatterRegistry, here is the link for the part answer:
Java Config equivalent for conversionService / FormattingConversionServiceFactoryBean
Also you would need (in some cases) to define to at least an empty Component for ConversionService, something like below:
#Component #Primary
public class MyConversionService extends DefaultConversionService implements ConversionService {
// an empty ConversionService to initiate call to register converters
}
This is to force spring container to initiate a call to:
class WebMvcConfigurerAdapter {
...
public void addFormatters(FormatterRegistry registry) {
//registry.addConverter(...);
}
}
Existing answers didn't work for me:
Customizing via WebMvcConfigurerAdapter.addFormatters (or simply annotating the converter with #Component) only works in the WebMvc context and I want my custom converter to be available everywhere, including #Value injections on any bean.
Defining a ConversionService bean (via ConversionServiceFactoryBean #Bean or #Component) causes Spring Boot to replace the default ApplicationConversionService on the SpringApplication bean factory with the custom bean you've defined, which will probably be based on DefaultConversionService (in AbstractApplicationContext.finishBeanFactoryInitialization). The problem is that Spring Boot adds some handy converters such as StringToDurationConverter to the standard set in DefaultConversionService, so by replacing it you lose those conversions. This may not be an issue for you if you don't use them, but it means that solution won't work for everyone.
I created the following #Configuration class which did the trick for me. It basically adds custom converters to the ConversionService instance used by Environment (which is then passed on to BeanFactory). This maintains as much backwards compatibility as possible while still adding your custom converter into the conversion services in use.
#Configuration
public class ConversionServiceConfiguration {
#Autowired
private ConfigurableEnvironment environment;
#PostConstruct
public void addCustomConverters() {
ConfigurableConversionService conversionService = environment.getConversionService();
conversionService.addConverter(new MyCustomConverter());
}
}
Obviously you can autowire a list of custom converters into this configuration class and loop over them to add them to the conversion service instead of the hard-coded way of doing it above, if you want the process to be more automatic.
To make sure this configuration class gets run before any beans are instantiated that might require the converter to have been added to the ConversionService, add it as a primary source in your spring application's run() call:
#SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(new Class<?>[] { MySpringBootApplication.class, ConversionServiceConfiguration.class }, args);
}
}
If you don't do this, it might work, or not, depending on the order in which your classes end up in the Spring Boot JAR, which determines the order in which they are scanned. (I found this out the hard way: it worked when compiling locally with an Oracle JDK, but not on our CI server which was using a Azul Zulu JDK.)
Note that for this to work in #WebMvcTests, I had to also combine this configuration class along with my Spring Boot application class into a #ContextConfiguration:
#WebMvcTest(controllers = MyController.class)
#ContextConfiguration(classes = { MySpringBootApplication.class, ConversionServiceConfiguration.class })
#TestPropertySource(properties = { /* ... properties to inject into beans, possibly using your custom converter ... */ })
class MyControllerTest {
// ...
}

Categories

Resources