Creating Bean inside Spring boot application using command line runner - spring

#SpringBootApplication
public class ReactiveCouchbaseExample1Application {
#Bean
CommandLineRunner employees(ApplicationContext context) {
EmployeeRepository repository = context.getBean(EmployeeRepository.class);
return args -> {
repository
.deleteAll()
.subscribe(null,null,()->{
Stream.of(new Employees(UUID.randomUUID().toString(), "Nikhil", 23, 3000L),
new Employees(UUID.randomUUID().toString(), "Shubham", 23, 3000L),
new Employees(UUID.randomUUID().toString(), "Anshul", 23, 3000L))
.forEach(employee->{
repository.save(employee)
.subscribe(System.out::println);
});
});
};
}
public static void main(String[] args) {
SpringApplication.run(ReactiveCouchbaseExample1Application.class, args);
}
I wants to run this piece of logic as soon my application context get loaded but when i started my app it shows this error.
Method employees in com.reactive.reactivecouchbaseexample1.ReactiveCouchbaseExample1Application required a bean of type 'com.reactive.repository.EmployeeRepository' that could not be found.
Can someone tell me how can I create a repository bean inside CommandLineRunner.
I also googled it but could'nt find any answers.
This is my repository
#Repository
public interface EmployeeRepository extends
ReactiveCouchbaseRepository<Employees, String>{
}

Scanned component must be in the same package as #SpringBootApplication annotated class, or its subpackage. I can only assume it is ReactiveCouchbaseExample1Application.class.
Maybe your repo is in different package, or you didn't enable component scan with #SpringBootApplication or #ComponentScan.

Related

Autowire not working with controller Spring Boot

Whenever I am trying to autowire a custom repository implementing JPA Repository within my controller class it is unable to do so and throwing a no bean def found error whereas if I am doing the same with any Service Class its working fine. Can anyone please explain to me why is it so?
Spring Boot
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-02-15 13:01:50.169 ERROR 16304 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field customerRepo in Controllers.MainController required a bean of type 'Repository.CustomerRepo' 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 'Repository.CustomerRepo' in your configuration.
```
#SpringBootApplication
#ComponentScan(basePackages = "Controllers")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
``````````````````
#RestController
#RequestMapping("/")
public class MainController {
#Autowired
private CustomerRepo customerRepo;
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String homePage() {
Customer testCustomer = new Customer();
testCustomer.setFirstName("csdcsdccs");
testCustomer.setLastName("csdcsdccs");
testCustomer.setMiddleName("csdcsdccs");
testCustomer.setAddressLine("csdcsdccs");
testCustomer.setCountry("csdcsdccs");
testCustomer.setPincode(713201);
testCustomer.setState("csdcsdccs");
testCustomer.setDateOfBirth(new Date(2019, 5, 13));
customerRepo.save(testCustomer);
return "inserted";
}
}
`````````````
#Repository
public interface CustomerRepo extends CrudRepository<Customer, Long> {
}
``````````````````````````
Spring application is unable to scan the repository. Could you please check if the repository is defined defined under the base package otherwise add Repository repository package also in #ComponentScan there.
#SpringBootApplication
#ComponentScan(basePackages = {"Controllers","Repository"})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Can you try #Component or #Repository annotations on you Repo?

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

CommandLineRunner required a bean that could not be found

I'm new to making APIs and Spring in general.
I'm trying to use CommandLineRunner in order to populate my repository but it says that it cannot find the required bean that I put in the parameter.
#SpringBootApplication
public class DemoApplication {
private static final Logger logger = LoggerFactory.getLogger(DemoApplication.class);
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
public CommandLineRunner initializeDB(StudentRepository studentRepository){
return (args)->{
studentRepository.save(new Student("John1", "Doe1", "asdasda1","Comp Sci1",21));
studentRepository.save(new Student("John2", "Doe2", "asdasda2","Comp Sci2",22));
studentRepository.save(new Student("John3", "Doe3", "asdasda3","Comp Sci3",23));
studentRepository.save(new Student("John4", "Doe4", "asdasda4","Comp Sci4",24));
studentRepository.save(new Student("John5", "Doe5", "asdasda5","Comp Sci5",25));
studentRepository.save(new Student("John6", "Doe6", "asdasda6","Comp Sci6",26));
logger.info("The sample data has been generated");
};
}
}
That is my application class and below is my repository class.
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.Student;
public interface StudentRepository extends JpaRepository<Student, Integer> {
}
Is there a basic thing that I am missing?
Thanks in advance
Easiest and wise thing to do
DemoApplication (or whichever class annotated with #SpringBootApplication) should reside at the root of the package structure
That means, for any other classes for which you want spring to manage it's bean's lifecycle, move that to a (sub)package of DemoApplication.
In other words, if your DemoApplication is in a package src/main/java/com/yourorg then StudentRepository should be in a (sub)package of src/main/java/com/yourorg
If the application class is not in a super package as the other classes, you have to specify all packages in the SpringBootApplication, which should be scanned (for component scanning, Spring Data repositories etc.).
#SpringBootApplication(scanBasePackages= {"package1", "package2"})
or for a typesafe approach
#SpringBootApplication(scanBasePackageClasses = {ClassFromPackage1.class, ClassFromPackage2.class})
Alternatively move all packages to a subpackage of the application class package, so that all the default mechanisms take place.

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