Injecting Spring Data Repository into arbitrary classes - java

I have created a few interfaces extending CrudRepository. I'd like to use them into a generic class that is not a bean. What I do currently is to inject them using #Autowired inside my RestController and then pass them down as method arguments to this generic class I'm talking about. Is there a better way to achieve this?

One approach is to make your unmanaged class extending SpringBeanAutowiringSupport and use #Autowired properties. If your application has a Spring web application context, it can then try to get the context from the current thread and resolve the #Autowired properties for you.

Related

How to call Spring Framework repositories methods

I know that there are questions similar to this one, but none of them have helped me. I'm following along this tutorial, and the part I can't wrap my mind around is:
#SpringBootApplication
public class Application {
private static final Logger log =
LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
#Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {
// save a couple of customers
...
// more lines, etc...
What I don't understand is where the repository passed into demo comes from. I know that the Autowired annotation can do something like that, but it isn't used at all here.
The more specific reason I ask is because I'm trying to adapt what they do here to an application I'm working on. I have a class, separate from all of the persistence/repository stuff, and I want to call repository methods like save and findAll. The issue is that the repository is an interface, so I can't instantiate an object of it to call the methods. So do I have to make a new class that implements the interface and create an object of that? Or is there an easier way using annotations?
When creating a #Bean, adding the repository in the parameters of the bean is enough to wire the repos in your bean. This works pretty much like adding #Autowired annotation inside a class that is annotated as #Component or something similar.
Spring works mostly with interface, since that is simplier to wire vs wiring concrete classes.
Can you try #Repository before the declaration of class? Worked for me in a Spring MVC structure.
#Repository
public class EntityDAOImpl implements EntityDAO{
...
}
The thing to wrap your head around is a Spring Boot application at startup time aims to resolve its dependancy tree. This means discovering and instantiating Beans that the application defines, and those are classes annotated with #Service, #Repository, etc.
This means the default constructor (or the one marked with #Autowire) of all beans is invoked, and after all beans have been constructed the application starts to run.
Where the #Bean annotation comes into play is if you have a bean which does not know the values of it's constructor parameters at compile time (e.g. if you want to wire in a "started at" timestamp): then you would define a class with an #Configuration annotation on it, and expose an #Bean method in it, which would return your bean and have parameters that are the beans dependencies. In it you would invoke the beans constructor and return the bean.
Now, if you want a certain method of some class to be invoked after the application is resolved, you can implement the CommandLineRunner interface, or you can annotate a method with #PostConstruct.
Some useful links / references:
https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
Running code after Spring Boot starts
Execute method on startup in Spring

Usage of #Component in case of inheritance

I have 2 scenarios where I would like to understand/confirm the usage of #Component:
Extending concrete class:
I have a concrete super class A and its sub-class Aa in my web application. I have annotated with Aa with #Component(value="aa") and #Scope(value=WebApplicationContext.SCOPE_SESSION). Also, I have annotated A class with #Component(value="a") and #Scope(value=WebApplicationContext.SCOPE_SESSION).
My question -> I am only doing applicationContext.getBean("aa"). I can skip the annotations in A class (please correct me if I am wrong), but I don't know why and how? My understanding has been that if a class is not annotated with #Component or defined in bean configuration file then Spring doesn't handle its instance management.
Abstract concrete class:
Same scenario and question as above just that in this case super class is an abstract class.
You have to register the beans via beans in a config or via component annotations (Repo or controller or service). If not the bean is not contained in your application context container.
#Component add a bean in the Spring registry. Then, you can retrieve this bean later.
If you don't use the bean, there is no need to add it to the bean registry. (so just remove #Component(value="a") and #Scope(value=WebApplicationContext.SCOPE_SESSION) )
On your use case, you set a scope to SESSION. It means that every time you create a session, Spring will instantiate your class (A / Aa) and put it on the session. As it is an instance of the class you don't need the super class instance (A) to be able to create the Aa instance.
With A beeing abstract, it is exactly the same thing, except if you try to scan it for Spring to pick it, Spring will throws an error saying A cannot be instantiated.

Cannot Autowire interface in spring boot app

I am developing a REST API using spring boot. Following is my package structure
Getting the following exception when I try to start my application
***************************
APPLICATION FAILED TO START
***************************
Description:
Field articleRepository in com.abc.service.ArticleService required a bean of type 'com.abc.dao.ArticleRepository' that could not be found.
Action:
Consider defining a bean of type 'com.abc.dao.ArticleRepository' in your configuration.
Following is my project structure-
com.abc
com.abc.bean
-Article.java
com.abc.controller
-ArticleController.java
com.abc.dao
-ArticleRepository.java (Interface)
com.abc.service
-ArticleService.java
com.abc.web
-AbcApplication.java (main Springboot class)
In AbcApplication.java as it is not in the root package, I have the below annotations
#SpringBootApplication
#ComponentScan(basePackages="com.abc.*")
I tried few ways -
I moved AbcApplication.java to root package com.abc but no success
Instead of interface(ArticleRepository.java) I made it a class, it is working
I keep it as interface but changed annotation from #Repository to #Service/Component still no success.
I am confused how it is working if I change it to class instead of interface.
#Repository
public interface ArticleRepository {
}
You don't have any bean for ArticleRepository. If you will use Spring Data Jpa you have to extend a type of Repository: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.
If you will use your own repository, you must implement it.
If you are using any RDBMS and if ArticleRepository repository is responsible for interacting with your database, then you need to either extends CrudRepository or JpaRepository in your ArticleRepository, then only Spring will be able to create the bean of ArticleRepository,and you will be able to autowire your repository.
If you are not extending any of CrudRepository or JpaRepository,then at the time of bean creation,ArticleRepository is only plain java interface and a plain interface can not be instantiated.
And as for your question:
Instead of interface(ArticleRepository.java) I made it a class, it is working
Its because when you declare it as a class, then Spring does instantiate a concrete class, so actual object will be created at the bean creation time and everything will be working as it should be.
Ideally you should have one class that implements interface ArticleRepository . Annotate that class with #Repository, spring will take care of wiring.
I was also encountered with the same issue. What I missed was the spring-boot-starter-jpa dependency. It worked when I added this dependency in the pom.xml file.
MyBatis gives you two samples to access your databases with spring boot.# Component or #Mapper.
Sample link:
mybatis-spring-boot-sample-xml
Suggestion:
Show your ArticleRepository code fully.
interface does not require any annotation (neither #repository not #Service).
If its a DAO file add #Repository annotation to the class implementing the corresponding interface.
And, if its a service then add #Service annotation to the class implementing the corresponding interface.

Manually resolve a dependency in Spring [Boot]

This seems like it should be trivial, but both Google and StackOverflow seem to be just as uncooperative as Spring docs (or I just don't know where to look).
My Spring Boot application needs to manually instantiate certain classes. Some of the classes have dependencies, so I can't use .newInstance(); instead, I figure I need to ask Spring to give me the instance from its DI container. Something like
Class<? extends Interface> className = service.getClassName();
Interface x = SpringDI.getInstance(className);
But I can't seem to find any way of doing this. What should I do?
EDIT
Class names are resolved dynamically, I have updated my sample pseuido-code to reflect that.
How about autowiring the ApplicationContext in the component in which you want to instantiate those classes? As ApplicationContext implements the BeanFactory interface, you can call the getBean() method.
Something like:
#Autowired
private ApplicationContext applicationContext;
[...]
applicationContext.getAutowireCapableBeanFactory().getBean(clazz_name);
I am not sure why you would want to do this, tho, as it defies the purpose of using Spring. (you can just not use Spring but use Java's reflection API)
Please refer to this part of the JavaDocs: http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html

Implementing Dependency Injection using Custom Annotation

I am working on a core java framework. I don't want to create instances directly inside the class which is why I want to use dependency injection.
I am thinking of declaring my custom annotations on the fields to be instantiated. And having a call back function which would create an instance and inject it into the field.
I had tried to create a custom annotation. But looks like there's no direct way to get a callback on the declared annotation. So, I was trying to scan the classes for that. But I ended up with this problem
Java Scanning Class for Annotation using Google Reflections
Please let me know if this is the right way of achieving this.
Since your question is tagged 'Spring', you can use Spring Framework's bean annotations (#Component / #Service / #Repository / ...), classpath scanning and #Autowired.
For example:
Setup classpath scanning on your spring config xml:
<context:component-scan base-package="com.mycompany.myapp" />
Create your bean to be scanned. Spring container will automatically create a singleton instance of this bean using default constructor:
#Repository
public class FooDAO {
...
}
Inject reference to above DAO instance using DI + autowiring
#Service
public class FooService {
#Autowired private FooDAO fooDAO;
...
}

Categories

Resources