Spring Boot #autowired does not work, classes in different package - spring

I have a Spring boot application.
I get the following error
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'birthdayController': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private com.esri.birthdays.dao.BirthdayRepository
com.esri.birthdays.controller.BirthdayController.repository; nested
exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type [com.esri.birthdays.dao.BirthdayRepository]
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)
~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at or
Following is code of my Repository class
package com.esri.birthdays.dao;
import com.esri.birthdays.model.BirthDay;
public interface BirthdayRepository extends MongoRepository<BirthDay,String> {
public BirthDay findByFirstName(String firstName);
}
Following is controller.
package com.esri.birthdays.controller;
#RestController
public class BirthdayController {
#Autowired
private BirthdayRepository repository;
Works if they are in same package. Not sure why

When you use #SpringBootApplication annotation in for example package
com.company.config
it will automatically make component scan like this:
#ComponentScan("com.company.config")
So it will NOT scan packages like com.company.controller etc.. Thats why you have to declare your #SpringBootApplication in package one level prior to your normal packages like this: com.company OR use scanBasePackages property, like this:
#SpringBootApplication(scanBasePackages = { "com.company" })
OR componentScan:
#SpringBootApplication
#ComponentScan("com.company")

Just put the packages inside the #SpringBootApplication tag.
#SpringBootApplication(scanBasePackages = { "com.pkg1", "com.pkg2", .....})
Let me know.

Try annotating your Configuration Class(es) with the #ComponentScan("com.esri.birthdays") annotation.
Generally spoken: If you have sub-packages in your project, then you have to scan for your relevant classes on project-root. I guess for your case it'll be "com.esri.birthdays".
You won't need the ComponentScan, if you have no sub-packaging in your project.

Try this:
#Repository
#Qualifier("birthdayRepository")
public interface BirthdayRepository extends MongoRepository<BirthDay,String> {
public BirthDay findByFirstName(String firstName);
}
And when injecting the bean:
#Autowired
#Qualifier("birthdayRepository")
private BirthdayRepository repository;
If not, check your CoponentScan in your config.

Spring Boot will handle those repositories automatically as long as they are included in the same package (or a sub-package) of your #SpringBootApplication class. For more control over the registration process, you can use the #EnableMongoRepositories annotation. spring.io guides
#SpringBootApplication
#EnableMongoRepositories(basePackages = {"RepositoryPackage"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

In my case #component was not working because I initialized that class instance by using new <classname>().
If we initialize instance by conventional Java way anywhere in code, then spring won't add that component in IOC container.

For this kind of issue, I ended up in putting #Service annotation on the newly created service class then the autowire was picked up.
So, try to check those classes which are not getting autowired, if they need the corresponding required annotations(like #Controller, #Service, etc.) applied to them and then try to build the project again.

By default, in Spring boot applications, component scan is done inside the package where your main class resides. any bean which is outside the package will not the created and thus gives the above mentioned exception.
Solution: you could either move the beans to the main spring boot class(which is not a good approach) or create a seperate configutation file and import it:
#Import({CustomConfigutation1.class, CustomConfiguration2.class})
#SpringBootpplication
public class BirthdayApplication {
public static void main(String [] args) {
springApplication.run(BirthdayApplication.class, args );
}
}
Add beans to these CustomConfiguration files.

I had the same problem. It worked for me when i removed the private modifier from the Autowired objects.

Another fun way you can screw this up is annotating a setter method's parameter. It appears that for setter methods (unlike constructors), you have to annotate the method as a whole.
This does not work for me:
public void setRepository(#Autowired WidgetRepository repo)
but this does:
#Autowired public void setRepository(WidgetRepository repo)
(Spring Boot 2.3.2)

There will definitely be a bean also containing fields related to Birthday
So use this and your issue will be resolved
#SpringBootApplication
#EntityScan("com.java.model*") // base package where bean is present
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

package com.test.springboot;
#SpringBootApplication
#ComponentScan(basePackages = "com.test.springboot")
public class SpringBoot1Application {
public static void main(String[] args) {
ApplicationContext context= SpringApplication.run(SpringBoot1Application.class, args);
=====================================================================
package com.test.springboot;
#Controller
public class StudentController {
#Autowired
private StudentDao studentDao;
#RequestMapping("/")
public String homePage() {
return "home";
}

When I add #ComponentScan("com.firstday.spring.boot.services") or scanBasePackages{"com.firstday.spring.boot.services"} jsp is not loaded. So when I add the parent package of project in #SpringBootApplication class it's working fine in my case
Code Example:-
package com.firstday.spring.boot.firstday;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication(scanBasePackages = {"com.firstday.spring.boot"})
public class FirstDayApplication {
public static void main(String[] args) {
SpringApplication.run(FirstDayApplication.class, args);
}
}

Related

How to use #Autowired in SpringBoot unit test

I am trying to unit test (using JUnit5 jupiter) a class developed in Java with Spring Boot that I would like to use the #Autowired annotation for convenience.
A very simplified version of it is as follow:
import org.springframework.stereotype.Component;
#Component
public class Demo {
public String get() {
return "hello";
}
}
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
#SpringJUnitConfig
class DemoTest {
#Autowired private Demo sut;
#Test
void Test() {
Assertions.assertEquals("hello", sut.get());
}
}
When I run the test this error occurs:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo.DemoTest': Unsatisfied dependency expressed through field 'sut'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.Demo' 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.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:659)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:417)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:119)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
...
How to prevent it?
To be noted: for this test, I do not want to start the full application using #SpringBootTest
Thanks,
Usually when you use #ContextConfiguration (which is a significant part of the stereotype #SpringJUnitConfig annotation) you should specify the configuration class from which the "Demo" component will be resolved.
Otherwise spring won't know which classes to load.
So you should basically create a configuration class (annotated with #Configuration) And specify what do you want to load there, for example with #ComponentScan
Haven't tested it but something like this should work:
#SpringJUnitConfig(MyTestConfig.class)
public class MyTest {
#Autowired Demo sut;
public void test() {... sut.doSomething(...); ...}
}
#Configuration
#ComponentScan(...) // here you should specify how to
// load the Demo class and maybe other classes as well
public class MyTestConfig {
}
Of course if instead of #Component you already use Java Config and define Demo class there you won't need to create this auxiliary MyTestConfig class and can load the configuration with the Demo class right away

Bean not found error : Unsatisfied dependency expressed through field

I have the below Main App:-
Both packages are in different module and i have "com.app.api is included in the pom.xml of com.app.batch
//commented #SpringBootApplication(scanBasePackages={"com.app.batch", "com.app.api"})
public class App
{
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
}
}
In com.app.api i have class ApiClass
#Service
public class ApiClass {}
in `com.app.batch i have
#Component
public class JobRunner implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
// TODO Auto-generated method stub
apiClass.getData(1111);
}
}
When i comment #SpringBootApplication(scanBasePackages={"com.app.batch", "com.app.api"}) i get the following error
Field apiClass in com.app.batch.config.JobRunner required a bean of
type 'com.com.api.ApiClass' that could not be found.
How can i resolve the issue without using scanBasePackages .I don't want to use scanBasePackages as the module can get added in future and it can get cumberson
If your not interested to use
#SpringBootApplication(scanBasePackages={"com.app.batch", "com.app.api"})
you need to change the package hierarchy so that spring scans the beans easily.
Your main SpringBootApplication class should be in com.app package
and remaining classes should be in sub-packages.
Like com.app.batch and com.app.api are sub-package of com.app
By using this kinda package hierarchy you no need scanBasePackages.
What is the package of the App class?
It needs to be in the base package so that Spring Boot Application scans all the packages inside it.
#SpringBootApplication annotation enables the following annotations/features on its own:
#EnableAutoConfiguration: enable Spring Boot’s auto-configuration mechanism
#ComponentScan: enable #Component scan on the package where the application is located
#Configuration: allow to register extra beans in the context or import additional configuration classes
For further details, you can read here

Spring: What happens when we move #ComponentScan to another class in the package?

I have the following classes:
#ComponentScan
public class CDPlayerConfig {
#Autowired
private static CompactDisc cd;
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
CompactDisc cd = context.getBean(CompactDisc.class);
System.out.println(cd);
}
}
public interface CompactDisc {
void play();
}
#Component
public class SgtPeppers implements CompactDisc {
public void play() {
System.out.println("play song....");
}
}
When I run the class CDPlayerConfig, the program runs successfully. However, if I remove the ComponentScan annotation to CompactDisc interface or SgtPeppers I get the following error:
Exception in thread "main"
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'CompactDisc' available
I think that ComponentScan annotation marks the package where Spring looks for beans. CDPlayerConfig, CompactDisc and SgtPeppers are all placed in the same package, so allegedly moving ComponentScan annotation from one class to another should not make a difference.
If so, why do I get an error?
For #ComponentScan to work you have to "tell" spring where to search, or it must find it with help of other, already loaded, #ComponentScan annotated class (your class must be then annotated also with #Component, #Configuration etc. so it could be found).
In your case, you register application context in the first line of main method - you have specified there to load CDPlayerConfig.class which is #ComponentScan annotated so now spring can automatically find other beans in the package:
ApplicationContext context =
new AnnotationConfigApplicationContext(CDPlayerConfig.class);
If you want to move #ComponentScan to another class, you have to change class registered in AnnotationConfigApplicationContext to some #ComponentScan annotated class:
SgtPeppers:
#Component
#ComponentScan
public class SgtPeppers implements CompactDisc {
(...)
Main in CDPlayerConfig:
ApplicationContext context =
new AnnotationConfigApplicationContext(SgtPeppers.class);
Note you should register context from concrete classes (not interfaces).
Also, above sample would work even without #ComponentScan annotation on SgtPeppers, but then beans defined in other classes from the package wouldn't be found.

Spring Boot: autowire beans from library project

I'm struggling to autowire beans from my custom library, imported with gradle.
after reading couple of similar topics I am still unable to find solution.
I have a Spring Boot project that depends on another project (my custom library with Components, Repositories etc...). This library is a Spring non-runnable jar, that consists primarily of domain Entities and Repositories. It doesn't have runnable Application.class and any properties...
When I start the application I can see that My 'CustomUserService' bean (from the library) is trying to be initialized, but the bean autowired in it failed to load (interface UserRepository)...
Error:
Parameter 0 of constructor in
com.myProject.customLibrary.configuration.CustomUserDetailsService
required a bean of type
'com.myProject.customLibrary.configuration.UserRepository' that could not
be found.
I've even tried to set 'Order', to load it explicitly (with scanBasePackageClasses), scan with packages and marker classes, add additional EnableJPARepository annotation but nothing works...
Code example (packages names were changed for simplicity)
package runnableProject.application;
import runnableProject.application.configuration.ServerConfigurationReference.class
import com.myProject.customLibrary.SharedReference.class
//#SpringBootApplication(scanBasePackages = {"com.myProject.customLibrary", "runnableProject.configuration"})
//#EnableJpaRepositories("com.myProject.customLibrary")
#SpringBootApplication(scanBasePackageClasses = {SharedReference.class, ServerConfigurationReference.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Classes from the library:
package com.myProject.customLibrary.configuration;
import com.myProject.customLibrary.configuration.UserRepository.class;
#Service
public class CustomUserDetailsService implements UserDetailsService {
private UserRepository userRepository;
#Autowired
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
...
package myProject.customLibrary.configuration;
#Repository
public interface UserRepository extends CustomRepository<User> {
User findByLoginAndStatus(String var1, Status var2);
...
}
Just found the solution.
Instead of defining base packages to scan from separate library, I've just created configuration class inside this library with whole bunch of annotation and imported it to my main MyApplication.class:
package runnableProject.application;
import com.myProject.customLibrary.configuration.SharedConfigurationReference.class
#SpringBootApplication
#Import(SharedConfigurationReference.class)
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
package com.myProject.customLibrary.configuration;
#Configuration
#ComponentScan("com.myProject.customLibrary.configuration")
#EnableJpaRepositories("com.myProject.customLibrary.configuration.repository")
#EntityScan("com.myProject.customLibrary.configuration.domain")
public class SharedConfigurationReference {}
You can create a folder called 'META-INF' in the 'resources' folder of your library and add a file called 'spring.factories' with the content org.springframework.boot.autoconfigure.EnableAutoConfiguration=<fully_qualified_name_of_configuration_file>. This will autoconfigure your library.
The accepted answer is too cumbersome. What you would need to do is implement your own custom auto-configuration in your library jar so that it is picked up in the classpath scan in the main application. More details here

Spring JPA Repository instance not created

I followed the example that the Spring organization provides here for Spring Data JPA.
This is my repository interface:
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
And this is a snippet of my Application class:
#Configuration
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class);
CustomerRepository repository = context.getBean(CustomerRepository.class);
I get the following error :
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [hello.CustomerRepository] is defined
I tried adding a #Repository annotation to CustimerRespository and the #ComponentScan annotation to the Application class, but result is the same.
I had the same problem and #EnableAutoConfiguration solved it.
If it doesn't work automatically, try disabling JpaRepositoriesAutoConfiguration and explicitly specify the repositories base package:
#EnableAutoConfiguration(exclude = {
JpaRepositoriesAutoConfiguration.class
}
#EnableJpaRepositories(basePackages = {"com.project.app.repositories"})
Good luck.
Maybe try adding on your configuration class
#EnableJpaRepositories
#EnableConfigurationProperties()
#EntityScan({"com.project.app.entities" })
try to add #EnableJpaRepositories and #ComponentScan annotations in Application class to see if adding them solve your problem.
If still it doesn't work, add #Configuration in your CustomerRepository interface and then in Application class add #Import(CustomerRepository .class).
let me know if works.

Resources