Bean not found error : Unsatisfied dependency expressed through field - spring

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

Related

Inject CRUD Repository in Spring

I can't Inject CRUD Repository in Spring.
Repository
#Repository
public interface EntityRepository extends CrudRepository<entity,Long>{
}
#Autowired EntityRepository eR
Error:
.. Required a Bean of Type EntityRepository that could not be found
Consider defining a bean of type 'EntityRepository' in your configuration.
My main
#SpringBootApplication
#ComponentScan({"de.xyz.*"})
#EntityScan("de.xyz.entities")
#EnableJpaRepositories("de.xyz.*")
//#EnableEurekaClient
public class Application extends SpringBootServletInitializer {
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
Another way of doing this is using the basePackages field; which is a field inside ComponentScan annotation.
#ComponentScan(basePackages = {"de.xyz.repository"})
public class Application extends SpringBootServletInitializer {
//
}
Step1 :
Try to include both the classes in the same package. This way you can narrow down the issue of component scanning. Remove all other annotations and keep only #SpringBootApplication
Note :
By default spring loads all the classes under the package of Application Class.
Step2 : See your dependencies, verify you have included the dependencies for JPA repositories.
Step3 : Post the GIT Hub link of the code, so that it can be looked further.
Otherwise add all the packages inside the component scan annotation , Like below.
#ComponentScan({ "a.b.c", "a.b.c.dao" })
As you have mentioned there is a configuration class which is creating the beans, try to include that class package in the same package or include it in component scan.
Hope this help.

SpringBoot excludeFilter not working with multiple configuration classes

I am developing a springboot app that has dependency on another springboot application. I want to include Most beans in the parent springboot app but one.
How can I exclude one springboot bean that the parent package has scanned without touching the ParentApplication class?
Ways I have tried but doesn't work:
1: using exclude filtering in my application class to filter out the particular bean class.
2: I also tried to exclude both the bean class and the parent configuration class.
3: add DisposableBean interface to the bean class I want to exclude and destroy it in run time.
below are my application starter configuration class and parent one.
my MyApplication.class:
package com.myapp;
#ComponentScan(
basePackages = {"com.parent",{my own packages..}},
excludeFilters= {
#ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value= {TheClassToExclude.class}),
#ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value= {ParentApplication.class})}
)
#SpringBootApplication(exclude=ParentApplication.class)
public class MyApplication{
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#PostConstruct
public void init() {
System.out.println("App is initialized.");
}
}
my ParentApplication.class
package com.parent;
#EnableRetry
#EnableScheduling
#SpringBootApplication(exclude = { HibernateJpaAutoConfiguration.class })
#ComponentScan(basePackages = {all the base package including the TheClassToExclude}
#PropertySource({all resources})
public class ParentApplication {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#PostConstruct
public void haha() {
System.out.println("configuration class created");
}
The console prints out: "configuration class created", so ParentApplication is initiated by springboot for some reason, so is the Class I want to exclude.
just for reference - I think that since both classes are annotated with #SpringBootApplication, thus are both #Configuration classes and will take part in the automatic Spring component scan - and it is not clear which of this classes will be scanned first in order to "exclude" the other one - unless... you explicitly specify the entry point, and thus, the first SpringBootApplication class to load like here
You can see which classes get instantiated by Spring component scanning and in what order by setting logging.level.org.springframework=DEBUG in application.properties

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

Execute CommandLineRunner outside #SpringBootApplication

This is based on https://spring.io/guides/gs/accessing-data-jpa/
I tried to move demo() in a different class in a different package (Application still on top of the filesystem hierarchy)
How do I make demo() run when i boot the project?
Application.java
package com.company.app
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
CommandLineRunner.java
package com.company.app.runner
public class Test {
#Bean
public CommandLineRunner demo() {
System.out.print("Run 1");
return (args) -> {
System.out.print("Run 2");
};
}
}
Add #Configuration to the Test class so that it is picked up when the classpath is scanned.
I haven't seen a Lambda for the CommandLineRunner before. Very nifty and saves having to create a class that specifically implements the CommandLineRunner.
Otherwise, you could implement CommandLineRunner to test and annotate as #Component.
#Component
public class ApplicationLoader implements CommandLineRunner {
#Override
public void run(String... strings) throws Exception {
System.out.print("Run 2");
}
}
* Update *
Answering the question in the comment with this update as I have more room to type...
#SpringBootApplication composes those other annotations as you indicated but those annotations are only applied to the specific class that it is defined on. The #Configuration annotation is telling Spring that the class defines beans that should be managed by the application context. The #ComponentScan tells spring to look through the classpath for classes that have specific annotations (e.g. #Component, #Service, #Configuration) and then act on those classes based on the type of annotation. the #EnableAutoConfiguration is the magic that loads appropriate beans based on the project dependencies (e.g. if mongo driver is on the classpath then create a MongoTemplate).

Resources