How to inject JpaRepository to not service class - spring

I have interface like this
#Repository
public interface CarRepository extends JpaRepository<Car, Long> {
}
In class adnotated #RestController Spring is able to wired with proper field.
But how can I do this if I want to create class without any adnotation in spring? I have to create implementation of this repository? If yes, can I do it like spring is?

Inject
private final ConfigurableApplicationContext configurableApplicationContext;
into the class instantiating your desired class. Then call:
YourClass yourClass = (YourClass) configurableApplicationContext.getBeanFactory().initializeBean(new YourClass(), "YourClassName");
yourClass will then hold an instance of YourClass which has been initialized as if it was a Spring #Component (or a #RestController, which is the same from the dependency-injection point of view).

#SpringBootApplication
public class MainApplication extends SpringBootServletInitializer implements ApplicationContextAware {
private static ApplicationContext appContext;
public static void main(String[] args) {
SpringApplication.run(CrawlerApplication.class, args);
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.appContext = applicationContext;
}
....
MainApplication.getAppContext().getBean(CarRepository.class)

Related

#Autowired not wiring my repository - null pointer exception

#SpringBootApplication
public class ImportCSV {
#Autowired
private static PersonRepository personRepository; //does not seem to work
public static void main(String args[]) throws IOException {
SpringApplication.run(ImportCSV.class, args);
Person person = new Person();
// Add a bunch of setters for person
personRepository.save(person); //personRepository is null
}
}
public interface PersonRepository extends JpaRepository<Person, Long>{
}
#Data
#Entity
#Table(name = "Persons")
#NoArgsConstructor
public class Person {
/*Declare relevant fields here*/
}
Please see above code. 'personRepository' is null. How do I fix this? What am I doing wrong -- how does Autowire work?
Spring does not inject into static fields. So you have to remove the static keyword from the personRepository field. The compiler will complain then, that you cannot access a non-static field from a static method. To solve this, implement the ApplicationRunner interface, which defines a run method. In that method, you can run all the code, that should be run after the Spring Boot application is started, e.g. for initializing any data in the database etc.
That would be the proper Spring Boot way to execute code after the application is started.
For even more cleaner code then, you can create a separate class, that implements the ApplicationRunner interface and move the code there.
Example:
#SpringBootApplication
public class ImportCSV implements ApplicationRunner {
#Autowired
private PersonRepository personRepository; //does not seem to work
public static void main(String args[]) throws IOException {
SpringApplication.run(ImportCSV.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {

Person person = new Person();
personRepository.save(person);
}
}

#Autowired is not working for CrudRepository

I have problems injecting a repository, there is no problem injecting a Service. Im injecting the repo in a service:
#Service
public class AuthorService {
#Autowired
private AuthorRepository repository;
public String getAll(){return "XXXXX";}
}
and the repository is:
public interface AuthorRepository extends CrudRepository<Author, Integer> {
}
And my code structure is the following:
with the main class:
#SpringBootApplication
public class AuthorBookGraphqlApplication {
public static void main(String[] args) {
SpringApplication.run(AuthorBookGraphqlApplication.class, args);
}
}
the error is thrown on start:
Field repository in com.author.book.graphql.demo.service.AuthorService required a bean of type 'com.author.book.graphql.demo.repository.AuthorRepository' that could not be found.
Update code as below
Spring will automatically import the beans into the container and inject to dependencies with these annotations.
#Component, #Controller, #Service and #Repository - Helps to define the beans so the container is aware of them and can inject them for you with #Autowired.
#Autowired - Handles only wiring part here.
#Service
public class AuthorService {
#Autowired
private AuthorRepository repository;
public String getAll(){return "XXXXX";}
}
#Repository
public interface AuthorRepository extends CrudRepository<Author, Integer> {}
Before class AuthorRepository, Let's put more annotation #Repository.

Why #PostConstruct not invoked in spring container?

I tried to add some entities in the db shema
config:
#Configuration
#ComponentScan(ApplicationConfig.basePackage)
public class ApplicationConfig {
public final static String basePackage = "test"
}
spring container invocation:
public class StartApp {
public static void main(String... args) throws Exception{
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
TestEntityRepository repository = (TestEntityRepository) context.getBean("testEntityRepository");
repository.save(new TestEntity("test"));
}
}
target class with annotation:
public class PersistenceService {
#Autowired
TestEntityRepository testEntityRepository;
#PostConstruct
public void initialize(){
//repository.deleteAll();
testEntityRepository.save(new TestEntity("test1"));
testEntityRepository.save(new TestEntity("test2"));
testEntityRepository.save(new TestEntity("test3"));
}
}
as the result in table only one record - "test". At the Tomcat all works fine.
https://github.com/GlebSa/TestSpringJPA
It seems your PersistenceServiceis not recognized as a Service. Can you add the #Service to PersistenceService?
#Service
public class PersistenceService {
...
}
Hope this help.

Create Spring boot standalone app

I'm trying to figure out how to build a Spring Boot standalone app. Of course to have things autowired requires some initial context starting point. If I just try to Autowire a class to run a job it is null even if I make it static.
Is there a way to use Spring #Services in a standalone non-web app?
#SpringBootApplication
public class MyApplication {
#Autowired
private static JobRunnerService job;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
job.send(); //job is null !
}
}
So first wired in a static JobRunnerService to the main running MyApplication the JobRunner(Service) Class has a non-static SshSessionService wired into it.
the SshSession(Service) finally just has a no-arg constructor.
#Service("jobRunnerService")
public final class JobRunner implements JobRunnerService{
#Autowired
private SshSessionService ssh;
#Autowired
public JobRunner(SshSessionService ssh){
this.ssh = ssh;
}
public void sendToAgent() { ....
}
#Service("sshSessionService")
public class SshSession implements SshSessionService {
public SshSession() {
}
}
It starts off being null at the JobRunnerService job reference.
Several different solutions comes to mind:
If you take a look at the SpringApplication.run() method you will notice that it returns a ApplicationContext. From that, you can fetch the JobRunnerService, e.g.
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
JobRunnerService job = ctx.getBean(JobRunnerService.class);
job.send();
}
}
Another solution is to use #PostConstruct annotation for the send() method:
#Service("jobRunnerService")
public class JobRunner implements JobRunnerService {
#PostConstruct
public void send() { ... }
}
However in your case, I would implement the ApplicationRunner interface, either as a separate bean which autowires the JobRunnerService and then calls its send() method
#Component
public class SendRunner implements ApplicationRunner {
#Autowired
private JobRunnerService job;
#Override
public void run(ApplicationArguments args) {
job.send();
}
}
or let the JobRunner implement the ApplicationRunner interface directly:
#Service("jobRunnerService")
public class JobRunner implements JobRunnerService, ApplicationRunner {
#Override
public void send() { ... }
#Override
public void run(ApplicationArguments args) {
send();
}
}
You haven't provided the code for JobRunnerService but I am assuming it has a default constructor and that it is annotated by #Component for Spring to figure it out as a bean before you can actually autowire it. your job is null probably because it's not able to find an autowired bean for JobRunnerService and that's probably because you don't have an identifier for Spring to scan and create bean of type JobRunnerService
You can use #Servicesor #Component to the JobRunnerService class then add annotation #ComponentScan("package of JobRunnerService") below #SpringBootApplication, see this link:
How to scan multiple paths using the #ComponentScan annotation?
You need a few steps to get your standalone app working:
A class with main() method.
A #SpringBootApplication annotation to your main class.
And a call to the SpringApplication.run() method.
package com.example.myproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication // same as #Configuration #EnableAutoConfiguration #ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
As noted, the #SpringBootApplication is a composite annotation which consist of #Configuration #EnableAutoConfiguration and #ComponentScan. In other words, it can be replaced by the three latter annotations. Alternatively, you can use the alias scanBasePackage or scanBasePackageClasses to customize which directories that should be used for component scanning.
The example is copied from the #SpringBootApplication paragraph in the Spring Boot reference docs (see link above). If you would like to quick start your project, complete with build scripts (Maven or Gradle), dependencies, etc, you can generate a project skeleton using the Spring Initializr
I'm trying to run as Thread/runnable now as mentioned in the Spring document 3. Task Execution and Scheduling..
import org.springframework.core.task.TaskExecutor;
public class TaskExecutorExample {
private class MessagePrinterTask implements Runnable {
private String message;
public MessagePrinterTask(String message) {
this.message = message;
}
public void run() {
System.out.println(message);
}
}
private TaskExecutor taskExecutor;
public TaskExecutorExample(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void printMessages() {
for(int i = 0; i < 25; i++) {
taskExecutor.execute(new MessagePrinterTask("Message" + i));
}
}
}
So in my case I'm trying...
#Service("jobRunnerService")
#Component
public class JobRunner implements JobRunnerService, ApplicationRunner{
#Autowired
public TaskExecutor taskExecutor;
#Autowired
private SshSessionService ssh;
private class JobTask implements Runnable{
public void run(){
Boolean success = connectToAgent();
if(success){
log.debug("CONNECTED!!!");
}
}
}
/**
* Construct JobRunner with TaskExecutor
* #param taskExecutor
*/
#Autowired
public JobRunner(TaskExecutor taskExecutor, SshSessionService ssh) {
this.taskExecutor = taskExecutor;
this.ssh = ssh;
}
private Map<String, String> sessionParams;
private final Logger log = LoggerFactory.getLogger(this.getClass());
#Override
public void run(ApplicationArguments args) {
/**
* Starting point of application
*
*/
taskExecutor.execute(new JobTask());
}
just getting org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.task.TaskExecutor] found for dependency
How can i get the imported lib to be accepted as a TaskExecutor Bean ??

How to access Spring context in jUnit tests annotated with #RunWith and #ContextConfiguration?

I have following test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/services-test-config.xml"})
public class MySericeTest {
#Autowired
MyService service;
...
}
Is it possible to access services-test-config.xml programmatically in one of such methods? Like:
ApplicationContext ctx = somehowGetContext();
This works fine too:
#Autowired
ApplicationContext context;
Since the tests will be instantiated like a Spring bean too, you just need to implement the ApplicationContextAware interface:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/services-test-config.xml"})
public class MySericeTest implements ApplicationContextAware
{
#Autowired
MyService service;
...
#Override
public void setApplicationContext(ApplicationContext context)
throws BeansException
{
// Do something with the context here
}
}
For non xml needs, you can also do this:
#RunWith(SpringJUnit4ClassRunner.class)
/* must provide some "root" for the app-context, use unit-test file name to the context is empty */
#ContextConfiguration(classes = MyUnitTestClass.class)
public class MyUnitTestClass implements ApplicationContextAware {
If your test class extends the Spring JUnit classes
(e.g., AbstractTransactionalJUnit4SpringContextTests or any other class that extends AbstractSpringContextTests), you can access the app context by calling the getContext() method.
Check out the javadocs for the package org.springframework.test.
It's possible to inject instance of ApplicationContext class by using SpringClassRule
and SpringMethodRule rules. It might be very handy if you would like to use
another non-Spring runners. Here's an example:
#ContextConfiguration(classes = BeanConfiguration.class)
public static class SpringRuleUsage {
#ClassRule
public static final SpringClassRule springClassRule = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Autowired
private ApplicationContext context;
#Test
public void shouldInjectContext() {
}
}

Resources