In our project we have a structure similiar to code below. If I uncomment the specified block Spring will fail to autowire PrintService in the PrintController
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'PrintController': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private printService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [MyPrintService] 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)}
Why is Spring having issues with it?
#Controller
public class PrintController {
#Autowired
private MyPrintService printService;
}
#Service
public class MyPrintService extends AbstractPrintService<MyModel> {
/* uncomment this block to get error
#Override
public void print(MyModel model){
//do stuff
}*/
}
public abstract class AbstractPrintService<M> extends CommonAbstractPrintService<M> {
}
public abstract class CommonAbstractPrintService<M> implements PrintService<M> {
#Override
public void print(M model){
//do common stuff
}
}
public interface PrintService<M> {
void print(M model);
}
The solution was to autowire the bean using interface. So instead of:
#Autowired
private MyPrintService printService;
I used
#Autowired
private PrintService printService;
And it suddenly worked. But I have no Idea why Spring was offended by that override. Would be glad if anyone could explain that! Thanks!
Related
main Class:
package *.*.*;
#SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
DBUtils.java
package *.*.*.dataaccess.dbutils;
#Service
public class DBUtils {
#Autowired
UserRepository userRepository;
public UserEntity getUserEntityById(String id) {
return userRepository.findById(id);
}
}
Repository Class:
package *.*.*.dataaccess.repository;
#Repository
public interface UserRepository extends JpaRepository<UserEntity, UserIdentity> {
UserEntity findById(String id);
}
and also UserEntity java class is in package *.*.*.dataaccess.dao;
Test Class:
#SpringBootTest
class UserApplicationTests {
#Autowired
DBUtils utils; // issue is with this
#Test
void contextLoads() {
}
}
While doing maven test for entire project and getting the below error:
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'DBUtils': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '...dataaccess.repository.UserRepository' 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 '...dataaccess.repository.UserRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I have used #Service on DBUtils and #Repository on JpaRepository but still getting the above error and using springboot is 2.4.1.
Can anyone please help here?
I am writing the integration tests with #WebFluxTest for my #RestController.
Here are my classes:
#RestController
#RequestMapping("/usager")
public class UsagerController {
#Autowired
private UsagerService usagerService;
#GetMapping
public Usager getUsager() {
return usagerService.create();
}
}
#Service
public class UsagerService implements CrudService<Usager, Integer> {
#Autowired
private UsagerRepository usagerRepository;
#Override
public JpaRepository<Usager, Integer> getRepository() {
return usagerRepository;
}
#Override
public Usager create() {
return new Usager();
}
}
#Repository
public interface UsagerRepository extends JpaRepository<Usager, Integer>, JpaSpecificationExecutor<Usager> {
}
#ExtendWith(SpringExtension.class)
#WebFluxTest(UsagerController.class)
#Import({ UsagerService.class, UsagerRepository.class })
#Tag(TestCase.INTEGRATION)
public class UsagerControllerIT {
#Autowired
private WebTestClient wtc;
#Test
public void getUsager_returnUsager() {
ResponseSpec rs = wtc.get().uri("/usager").exchange();
rs.expectStatus().isOk();
rs.expectHeader().contentType(MediaType.APPLICATION_JSON);
rs.expectBody(Usager.class).isEqualTo(new Usager());
}
}
I get the following exception:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.dsi.bibliosys.biblioback.repository.UsagerRepository]: Specified class is an interface
I don't understand why Spring can't inject the repository.
Does somebody have an idea ?
I tried another approach using #SpringBootTest. Here is my new test class :
#ExtendWith(SpringExtension.class)
#SpringBootTest
#Tag(TestCase.INTEGRATION)
public class UsagerController02IT {
#Autowired
private UsagerController usagerController;
#Test
public void getUsager_returnUsager() {
WebTestClient wtc = WebTestClient.bindToController(usagerController).build();
ResponseSpec rs = wtc.get().uri("/usager").exchange();
rs.expectStatus().isOk();
rs.expectHeader().contentType(MediaType.APPLICATION_JSON);
rs.expectBody(Usager.class).isEqualTo(new Usager());
}
}
I get this exception:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.dsi.bibliosys.biblioback.controller.UsagerController': Unsatisfied dependency expressed through field 'usagerService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.dsi.bibliosys.biblioback.service.entity.UsagerService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I don't understand why UserService is not available in the application context.
Thanks for your help.
This looks very similar to this. I'd suggest investigating your test configuration and adding it if appropriate.
A quote from Spring on #WebFluxTest
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to WebFlux tests (i.e. #Controller, #ControllerAdvice, #JsonComponent, Converter/GenericConverter, and WebFluxConfigurer beans but not #Component, #Service or #Repository beans).
I have a simple spring app with one controller
#RestController
public class UserController {
// #Autowired
// UserServiceImpl userService;
#RequestMapping(value="/getUser", method = RequestMethod.GET)
public String getUser(){
// return userService.greetUser();
return "Hello user";
}
It works when I start it. If I uncomment #Autowired and run with the first return statement using UserService it also works.
My Service interface
#Service
public interface UserService {
String greetUser();
void insertUsers(List<User> users);
}
and implementation
#Service
public class UserServiceImpl implements UserService{
#Override
public String greetUser() {
return "Hello user";
}
}
But when I test it, the app falls with the following errors
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController': Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.service.UserServiceImpl' 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 'com.example.demo.service.UserServiceImpl' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
The test class
#RunWith(SpringRunner.class)
#WebMvcTest
public class DemoApplicationTests {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldReturnHelloString() throws Exception{
this.mockMvc
.perform(get("/getUser"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("Hello user"));
}
}
Also, if I remove
// #Autowired
// UserServiceImpl userService;
and run test with second return statement, the test execute without error. I understand that the problem is in the UserServiceImpl, but I don't know what it is. What do I need to correct?
You should try to autowire your bean by an interface, not implementation
#Autowired
UserService userService;
And also you should remove #Service from UserService interface
I Create the bean by configuration with out name
#Configuration
#ConfigurationProperties(prefix = "mysql")
public class DbConfiguration extends BaseDbConfiguration {
#Bean//(name = "fix")
#Override
public DbClient createClient() {
return super.createClient();
}
}
usage:
#Autowired
private DbClient dbClient;
when I running application it can't start up
And throw NoSuchBeanDefinitionException:
No qualifying bean of type [DbClient] 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)}
But I fix it by add name, why??
#Bean(name = "fix")
I also add a test such like this:
public class TestCreate {
#NotNull
private int test;
public Test createTest() {
return new Test(this.test);
}
}
it configuration like this:
#Configuration
#ConfigurationProperties(prefix = "test")
public class TestConfiguration extends TestCreate {
#Override
#Bean
public Test createTest() {
return super.createTest();
}
}
And autowired like this:
#Autowired
private Test test;
However, this test may work well
It also create Bean without name and Autowired with out Qualifier
Please Tell me why....thanks
Sorry.
I have found the results:
Overriding bean definition for bean 'createClient': replacing ...
So Spring-Boot will create Bean by FunctionName rather than returning ObjectName.
Application-Context is correctly setup!
Heres my class scenario
public interface IManager
{
public void doStuff();
}
#Component
public abstract class ManagerAction implements IManager
{
#Async
#Override
public void doStuff()
{
//doing stuff
}
public abstract manageWorker();
}
#Component
public class Working extends ManagerAction
{
#Override
public manageWorker()
{
//some busy code
}
}
#Component
public class NotWorking extends ManagerAction
{
#Override
public manageWorker()
{
//some busy code
}
}
#Service
public class BusinessWorker
{
#Autowire
private IManager manager_;
public void preformTasks()
{
manager_.doStuff();
}
}
Heres my error
ERROR [main] (ContextLoader.java:307) - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'BusinessWorker': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.B
eanCreationException: Could not autowire field: private com.background.IManager com.background.BusinessWorker.manager_; nested exception is org.springframework.beans.
factory.NoSuchBeanDefinitionException: No matching bean of type [com.background.IManager] 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)}
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.background.IManager com.background.BusinessWorker.manager_;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.background.IManager] 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:506)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284)
... 28 more
Application-Context
<mvc:annotation-driven />
<task:annotation-driven />
<context:annotation-config />
<context:component-scan base-package="com.background" />
The error message says it all: you try to autowire an instance of IManager, but two different Spring components implement this interface, so Spring doesn't know which one to autowire. You need to use the #Qualifier annotation to specify which one you want Spring to autowire.