I have a SpringBoot app (REST Architecture )
I have this service defined that uses Constructor Dependency Injection
#Service
#Slf4j
public class HostelService {
private final HostelRepository hostelRepository;
HostelService(HostelRepository hostelRepository) {
this.hostelRepository = hostelRepository;
}
}
I want to use it in a integration test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class HostelServiceIntegrationTest {
public static final String Hostel_1 = "Hostel::1";
#Autowired
protected HostelRepository hostelRepository;
#Autowired
private HostelService hostelService;
//...
}
#Repository
public interface HostelRepository extends CouchbaseRepository<Hostel, String> {
}
but I have this error:
..Unsatisfied dependency expressed through constructor parameter 0;
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'io.clouding.repository.HostelRepository' available: expected at
least 1 bean which qualifies as autowire candidate. Dependency
annotations: {}
and on the Application:
#SpringCloudApplication
#SpringBootApplication
#EnableJpaRepositories("io.clouding.repository")
#ComponentScan(basePackages = { "io.clouding.repository" })
public class Application implements WebMvcConfigurer {
..
}
I hope your problem is that your bean, HostelRespository is not getting created. And it's a CouchbaseRepository. I hope it's not even created in non-test environment also.
What you have to do is, instead of
#EnableJpaRepositories("io.clouding.repository")
add
#EnableCouchbaseRepositories(basePackages = {"io.clouding.repository"})
It will help run-time to create the bean for you. So your specific problem will be solved.
Note:
Please note that, if you haven't still configured the underlying configurations needed for spring-data-couchbase, you might see some other errors after fixing this, that you have to fix by configuration. You may refer this.
The error says it, you probably have a RequestRepository and the error is inside it; check the constructor/dependencies in it and see if something is not being injected or show the RequestRepository and the full error stack trace.
Related
I'm using a 3rd party dependency in my Spring Boot project (version 2.6.3) which has the following classes:
#ConditionalOnProperty(prefix = "spring.cloud.vault", name = "enabled", matchIfMissing = true)
#AutoConfigureAfter(ApacheHttpClientAutoConfiguration.class)
#Configuration
public class VaultServiceAutoConfiguration {
// ...
}
#Configuration
#EnableConfigurationProperties({VaultServiceProperties.class})
#ConditionalOnBean(VaultServiceAutoConfiguration.class)
public class VaultServiceFacadeConfiguration {
private final VaultServiceProperties vaultServiceProperties;
#Autowired
public VaultServiceFacadeConfiguration(VaultServiceProperties properties) {
this.vaultServiceProperties = properties;
}
#Bean
#ConditionalOnMissingBean(VaultServiceFacade.class)
public VaultServiceFacade vaultServiceFacade(
#Qualifier("runtime") VaultServiceTemplate vaultServiceTemplate) {
// ...
}
}
I set spring.cloud.vault.enabled=true in my bootstrap.yml.
In my project I import the dependency and created a component class:
#Component
public class MyVault {
private VaultServiceFacade vaultServiceFacade;
public MyVault(VaultServiceFacade vaultServiceFacade) {
this.vaultServiceFacade = vaultServiceFacade;
}
}
in order to use VaultServiceFacade bean which provides methods to interact with Hashicorp Vault instance. The problem is that I get this error: No qualifying bean of type 'other.package.VaultServiceFacade' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I don't understand why I get his error because my main class is annotated with #SpringBootApplication so that auto-configuration is enabled. In addition if I try to inject VaultServiceAutoConfiguration bean it works:
#Component
public class MyVault {
private VaultServiceAutoConfiguration v;
public MyVault(VaultServiceAutoConfiguration v) {
this.v = v;
}
}
EDIT: I did notice that the dependency has a file spring.factories with the following code:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
other.package.VaultServiceAutoConfiguration
So maybe only VaultServiceAutoConfiguration is "whitelisted" for auto-configuration, so I need to understand how to allow other beans from other.package to be injected in my project.
EDIT2: I managed to get this working by adding #ComponentScan on the MyVault class:
#ComponentScan("other.package")
#Component
public class MyVault {
private VaultServiceFacade vaultServiceFacade;
public MyVault(VaultServiceFacade vaultServiceFacade) {
this.vaultServiceFacade = vaultServiceFacade;
}
}
I still don't understand why the ComponentScan works only on when added to MyVault class but is if I scan for this package from main it class it doesn't work:
#SpringBootApplication(scanBasePackages = {"other.package"})
public class Application {
// ...
}
#ComponentScan just works because you're very directly asking Spring to scan said package for any beans which it straight up does.
I can't tell why #SpringBootApplication(scanBasePackages = {"other.package"}) doesn't work without trying it for myself but I guess the error you get is that the other.package beans get created and instead all other beans fail to exist (after all other.package is not the base package).
Finally, why doesn't you preferred conditional approach work?
Hard to tell without a simplified sample app to work with. I doubt it's because of VaultServiceAutoConfiguration, I've created a simplified project where the offending bean lies directly in said class and it loads just fine. Try moving your VaultServiceFacade definition to VaultServiceAutoConfiguration and remove #AutoConfigureAfter(ApacheHttpClientAutoConfiguration.class), if that works you know it's something in VaultServiceFacadeConfiguration (or #AutoConfigureAfter(ApacheHttpClientAutoConfiguration.class) itself, maybe #EnableConfigurationProperties({VaultServiceProperties.class})?
Also, I used application.properties instead of bootstrap.yml but that's unlikely to be it.
Feel free to send a sample simplified project to work on and test your assumptions
As the default value for the property is already true, I would not set it at all.
In order to explicitly configure the Facade try to
#Import(VaultServiceFacadeConfiguration.class)
in your SpringBootApplication.
Please check your dependencies. "other.package" looks very strange and does not look like a package name used by HashiCorp.
I want to create a #SpringBootTest that makes use of my full configuration structure.
Problem: I'm creating an #Bean SecurityWebFilterChain that requires a ServerHttpSecurity, which is somehow missing in a test:
#SpringBootApplication
public class MainApp { ... }
//for simple testing I started with anonymous auth
#Configuration
public class ReactiveSecurityConfiguration {
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http.anonymous()
.and().csrf().disable()
.build();
}
}
#SpringBootTest
public class TestClass {
#Test
public void test() {
}
}
Result:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'securityWebFilterChain' defined in class path resource [ReactiveSecurityConfiguration.class]:
Unsatisfied dependency expressed through method 'securityWebFilterChain' parameter 0;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.security.config.web.server.ServerHttpSecurity' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Update
I discovered if I add the following annotations to my Test Class, the testmethod works without errors. But is that intentional?
#EnableWebFlux
#EnableWebFluxSecurity
#SpringBootTest
public class TestClass { }
I'm not certain how your project is arranged, but no, it's not intentional. You can take a look at Spring Security's Reactive Sample that demonstrates this.
It may be that your TestClass is not finding the #SpringBootConfiguration annotation attached to MainApp.
I have a spring-boot-starter-web dependency pulled somewhere in the classpath. Removing it resolved the problem.
If both web and webflux dependency should be kept, it's still possible to run a test in reactive only, with:
#SpringBootTest(properties = "spring.main.web-application-type=REACTIVE")
class MyWebFluxTests {
// ...
}
I have a MyService class which has repository field supposed to be injected.
public class MyService {
#Autowired
private MyRepository repository;
// ...ommited
}
And there is MyRepository interface only implemented by MyRepositoryImpl class with #Mapper annotation of MyBatis.
public interface MyRepository {
// ...ommited
}
#Mapper
public interface MyRepositoryImpl extends MyRepository {
// ...ommited
}
When I try to start SpringBootApplication, NoUniqueBeanDefinitionException is thrown.
#SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
#MapperScan(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
(...omitted)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'com.example.MyService':
Unsatisfied dependency expressed through field 'repository';
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.example.MyRepository' available:
expected single matching bean but found 2: com.example.MyRepositoryImpl,com.example.MyRepository
(...omitted)
Why is MyRepository interface registered as one of bean even though it doesn't have #Component annotation nor isn't included any bean configurations?
And I found that everything work fine if I don't use FullyQualifiedAnnotationBeanNameGenerator as nameGenerator.
Any ideas?
There can be many other ways to mark an interface as a bean. Some of them are:
#RepositoryDefinition above MyRepository interface
MyRepository extends CrudRepository or JpaRepository
Check if any of these exist.
Update 1:-
The problem seems to be in #MapperScan. What it does is scans for all the interfaces in a package and register them as bean; and if I am not wrong MyRepository and MyRepositoryImpl are in the same package. That's the reason why 2 beans are being created with names com.example.MyRepositoryImpl, com.example.MyRepository and basically both are of same type as MyRepositoryImpl extends MyRepository.
Now when you are using #Autowired on repository field of MyService, it gets confused as in which one to inject. To resolve this the easiest approach is to use #Primary over MyRepositoy which will give that interface a priority while injecting. Another approach is to use #Qualifier("uniqueName") over both the interfaces and also above repository field of MyService along with #Autowired specifying which one you want to inject. You can visit official documentation from here to learn more.Hope this helps a bit .
Spring is not able to figure out the bean whose class is supposed to be implementing the Repository interface.
Put the annotation #Repository above the RepositoryImpl Class. It will find it.
I have been using Spring for a number of months now, but still do not understand some of the various subtleties imposed by the framework.
I am trying to execute a unit test for a class and am running into the often seen error message and exception:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 1 of constructor in <package>.MessagingManager required a bean of type 'boolean' that could not be found.
Action:
Consider defining a bean of type 'boolean' in your configuration.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'boolean' available: expected at least 1 bean which qualifies as autowire candidate.
The unit test class (messagingManager is the SUT):
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = {MessagingManager.class})
public class TestMessagingManager {
#Autowired
private MessagingManager messagingManager;
...
A configuration class:
#Configuration
#EnableScheduling
#EnableAsync
#ComponentScan({"<package 1>"})
public class ServiceConfigurer {
...
#Value("${service.name}")
private String serviceName;
...
#Bean(name = "messagingManager")
public MessagingManager messagingManager() {
return new MessagingManager(serviceConfig(), "MISSION_PLANNER".equals(serviceName));
}
...
#Bean
public ServiceConfig serviceConfig() {
return config.getServiceByName(serviceName);
}
...
}
The SUT class:
public class MessagingManager {
...
public MessagingManager(ServiceConfig serviceCfg, boolean transactional) {
...
}
...
}
I tried using org.springframework.test.util.ReflectionTestUtils.setField() to set the serviceName field in the ServiceConfigurer class, but that did not help. I suspect it doesn't work because the problem is occurring when DI is involved and that the reflection utility usage is "too late". Just a guess.
What am I doing wrong?
If I were to entertain the idea of "creating a bean of type boolean", how do I define a bean that simply holds a boolean value, that's set based on the value of another configured piece of information? Are there alternatives?
With
#SpringBootTest(classes = { MessagingManager.class })
Spring tries to add a bean of type MessagingManager to your context. It does so by invoking the only available constructor. Spring now want to inject beans of type ServiceConfig and boolean as constructor parameters. But this fails because there is no bean of type boolean in the test context.
One solution would be to change this line to
#SpringBootTest(classes = { ServiceConfigurer.class })
because ServiceConfigurer knows how to construct a bean of type MessagingManager.
To inject properties to your test you can add
#TestPropertySource(properties = { "service.name=example" })
to your test class.
I'm a Spring noob and I'm struggling with it.
Basically before starting develop my Server with Spring in conjunction with JPA I tried to start a simple example just to get used to this framework.
I've already get succeded in make Spring working with some frameworks as Log4J, Swagger and others. Now I'm trying to work with JPA and there are some points i can find out the solution.
I saw some blogs on how to develop with it and from all thousands options i choose to create my Repository Interfece and extend Repository<T, ID>. You can see my code bellow:
package com.example.model;
#Entity
public class Person {
#Id
public Integer id;
public String name;
public Person(){}
}
package com.example.repository;
public interface PersonRepository extends Repository<Person, Integer> {
Collection<Person> findAll();
}
package com.example.controller;
#RestController
public class PersonController {
#Autowired
private PersonRepository repo;
#RequestMapping(value = "/persons", method = RequestMethod.GET)
public Collection<Person> getAll() {
return repo.findAll();
}
}
package com.example;
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
And I also have the application.properties file:
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/test_db
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driver-class-name=org.postgresql.Driver
When I put the server running I get the following exception:
: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.repository.PersonRepository com.example.controllers.PersonController.repo; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.example.repository.PersonRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations:
: Closing JPA EntityManagerFactory for persistence unit 'default'
: Stopping service Tomcat
: Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.repository.PersonRepository com.example.controllers.PersonController.repo; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.example.repository.PersonRepository] 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 created a Github Repository to share the code here.
Any clue about what am I doing wrong?
First thing here is why you need to implements the base interface Repository as doing so, you will not have usual CRUD operations. For such operations is better to implements CrudRepository. Since you implement CrudRepository no need to define a findAll() Method and many well known others you can find in doc mentioned.
Furthermore, when using #SpringBootApplication Spring boot use default values. If you see the #SpringBootApplication definition you will see that :
Many Spring Boot developers always have their main class annotated with #Configuration, #EnableAutoConfiguration and #ComponentScan. Since these annotations are so frequently used together (especially if you follow the best practices above), Spring Boot provides a convenient #SpringBootApplication alternative.
The #SpringBootApplication annotation is equivalent to using #Configuration, #EnableAutoConfiguration and #ComponentScan with their default attributes: [...]
That means when using default values for ComponentScan your packages sturctures shloud be as following :
com.example.model -> your entities
com.example.repositoriy -> your repositories
com.example.controller -> controllers
com.example -> MainApplication class
Here is an example for default project structure
The main Application Class should be in higher level package then the others. Unless you have to specify packages location with #ComponentScan.
As you are beginner with the framework. I suggest you to always see classes definitions in official documentation.
UPDATE :
Here is an example from one of my spring boot projects
Also see this spring guide for JPA
Just annotate your interface with #Repository. And if that doesnt work try adding #EnableJPARepositories to the main class.
Try adding the #Repository annotation to your PersonRepository, that could be the reason it doesn't find it.
You need to annotate your PersonRepository interface with #Respository, otherwise the spring context won't recognize it or create an implementation for it.