How to use unit of work in rest controller properly? - spring

public interface CourseRepo extends CrudRepository<Course, Long> {
}
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class UnitOfWork {
CourseRepo courses;
StudentRepository students;
StudyProgramRepository studyPrograms;
StudySchemeRepo studySchemes;
FeeStructureRepository feeStructures;
}
#RestController
public class TestController {
#Autowired
UnitOfWork uow;
#GetMapping("/addcr")
public String addCourse() {
Course cr = new Course();
cr.setTitle("DingDong course");
uow.getCourses().save(cr);
return "course Added..!!" ;
}
APPLICATION FAILED TO START
***************************
Description:
Field uow in com.srs.TestController required a bean of type 'com.srs.uow.UnitOfWork' 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 'com.srs.uow.UnitOfWork' in your configuration.
if i remove autowired and add a bean
#RestController
public class TestController {
#Bean
public UnitOfWork uow() {
return new UnitOfWork();
}
#GetMapping("/addcr")
public String addCourse() {
Course cr = new Course();
cr.setTitle("DingDong course");
uow().getCourses().save(cr);
return "course Added..!!" ;
}
java.lang.NullPointerException: Cannot invoke "com.srs.jpa.CourseRepo.save(Object)"
because the return value of "com.srs.uow.UnitOfWork.getCourses()" is null
i tried both autowired and in this case how can i use autowired or bean properly ?

Your class need to be annotated with #Component to be used with DI provider by #Autowired annotation
For the same reason each repository of your class need to be annotated with #Autowired

The Error Message gives the answer.
Field uow in com.srs.TestController required a bean of type 'com.srs.uow.UnitOfWork' that could not be found.
spring is searching for a bean from type UnitOfWork. You have to add this class to the application context from spring boot. To accomplish this you have to annotate the class UnitOfWork with #bean or #Data if you use lombok.
After this the spring application can find the Class UnitOfWork and auto wire it.

Since UnitOfWork (a somewhat misleading name in the JPA context) autowires data repositories, it has to be a Spring Bean itself.
The easiest and most common way is to annotate the class with one of the annotations #Service, #Component or #Bean, depending on the semantic of the class. There are also other ways, like the #Bean on method-level as you used.
To use the fully initialized bean you need to autowire it where you want to use it, not calling the create method. E.g. calling uow() as in your sample, bypasses the Spring Bean mechanism and creates a new instance, which hasn't been fully initialized (thus the NullPointerException).
Usually, the beans are autowired as fields, sometimes they are autowired in mehtod parameters (especially when working with #Bean on method-level in the same class).
E.g.
#Component
#Getter
#RequiredArgsConstructor
public class UnitOfWork {
private final CourseRepo courses;
private final StudentRepository students;
private final StudyProgramRepository studyPrograms;
private final StudySchemeRepo studySchemes;
private final FeeStructureRepository feeStructures;
}

Related

Spring Boot Autowired failed - null

I have 3 classes which are found in different packages in a spring boot application as follows:
Why does #Autowired work in certain classes only?Anything I am doing wrong?
#Configuration
public class Configurations{
#Autowired
Prop prop; //works fine
#Bean
//other bean definitions
}
#Component
public class Prop{
public void method(){};
}
public class User{
#Autowired
Prop prop; //does not work, null
public void doWork(){
prop.method();
}
}
I have also tried the #PostConstruct, but same result
public class User{
#Autowired
Prop prop; //does not work, null
#PostConstruct
public void doWork(){
prop.method();
}
}
The #Autowired annotation works only if Spring detects that the class itself should be a Spring bean.
In your first example you annotated Configurations with the #Configuration annotation. Your User class on the other hand does not have an annotation indicating that it should be a Spring bean.
There are various annotations (with different meanings) to make your class being picked up by the Spring container, some examples are #Service, #Component, #Controller, #Configuration, ... . However, this only works if your class is in a package that is being scanned by the Spring container. With Spring boot, the easiest way to guarantee that is by putting your User class in a (sub)package of your main class (the class annotated with #SpringBootApplication).
You can also manually create your bean by writing the following method in your Configurations:
#Bean
public User user() {
return new User();
}
In this case you don't have to annotate your User class, nor do you have to make sure that it is in a package that is being scanned.

#Autowire does not work. Could not autowire, multiple bean with same name

I am trying to create spring project in intellij. I have following interface:
DAO
public interface DAO<T> {
public int create(T object);
public T read(int id);
public int update(int id, T object);
public int delete(int id);
}
I have two other classes, Employee and Customer that implements this interface with #Repository annotation on them.
When I try to #Autowire the DAO interface in my controller class, IntelliJ shows compile time error "could not autowire, multiple bean of DAO type found".
What am I doing wrong here?
When you set the #Autowired on property it will use the autowire byType to resolve the collaborating bean. So in the case as you've described it will produce a conflict of more than one qualifying bean.
To resolve this, you should use #Qualifier annotation, and add name to your #Repostiory annotation, something like
class YourController
{
#Qualifier("customer")
#Autowired
private Dao customerRepository;
}
#Repository("customer")
class Customer implements Dao{}
#Repository("employee")
class Employee implements Dao{}

Spring annotation based bean injection

So this is basically what I am trying to achieve: Inject User with constructor into UserClass. But it is throwing "No default constructor found" error. As I suspect if I add #Autowired to class User constructor it expects injection there so I'm not really sure where the problem is.
The question might be too basic so you can redirect me to older such questions. There is very little information on annotation based DI.
#Component
public class UserClass {
public User user;
#Autowired
public UserClass(User user) {
this.user = user;
}
}
#Configuration
public class DIconfig {
#Bean
public User getUser() {
return new User('John');
}
}
#Component
public class User {
public String name;
//#Autowired
public User(String name) {
this.name = name;
}
}
Thank you for your time.
You define two beans of the class User, one with #Component, and one with #Bean. The bean configuration with #Bean is fine so far, however the bean definition with #Component is indeed lacking the default constructor. Every bean which is defined with #Component must either have a default constructor or a constructor where all dependencies are autowired. Neither is the case with your bean. So either add a default constructor or remove the #Component and only create beans of that class with an #Bean method.

#Autowire failing with #Repository

I am not being able to make #Autowire annotation work with a #Repository annotated class.
I have an interface:
public interface AccountRepository {
public Account findByUsername(String username);
public Account findById(long id);
public Account save(Account account);
}
And the class implementing the interface annotated with #Repository:
#Repository
public class AccountRepositoryImpl implements AccountRepository {
public Account findByUsername(String username){
//Implementing code
}
public Account findById(long id){
//Implementing code
}
public Account save(Account account){
//Implementing code
}
}
In another class, I need to use this repository to find an account by the username, so I am using autowiring, but I am checking if it works and the accountRepository instance is always null:
#Component
public class FooClass {
#Autowired
private AccountRepository accountRepository;
...
public barMethod(){
logger.debug(accountRepository == null ? "accountRepository is NULL" : "accountRepository IS NOT NULL");
}
}
I have also set the packages to scan for the components (sessionFactory.setPackagesToScan(new String [] {"com.foo.bar"});), and it does autowire other classes annotated with #Component for instance, but in this one annotated with #Repository, it is always null.
Am I missing something?
Your problem is most likely that you're instantiating the bean yourself with new, so that Spring isn't aware of it. Inject the bean instead, or make the bean #Configurable and use AspectJ.
It seems likely that you haven't configured your Spring annotations to be enabled. I would recommend taking a look at your component scanning annotations. For instance in a Java config application:
#ComponentScan(basePackages = { "com.foo" })
... or XML config:
<context:annotation-config />
<context:component-scan base-package="com.foo" />
If your FooClass is not under the base-packages defined in that configuration, then the #Autowired will be ignored.
As an additional point, I would recommend trying #Autowired(required = true) - that should cause your application to fail on start-up rather than waiting until you use the service to throw a NullPointerException. However, if annotations are not configured, then there will be no failure.
You should test that your autowiring is being done correctly, using a JUnit test.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes = MyConfig.class,
loader = AnnotationConfigContextLoader.class)
public class AccountRepositoryTest {
#Autowired
private AccountRepository accountRepository;
#Test
public void shouldWireRepository() {
assertNotNull(accountRepository);
}
}
This should indicate whether your basic configuration is correct. The next step, assuming that this is being deployed as a web application, would be to check that you have put the correct bits and pieces in your web.xml and foo-servlet.xml configurations to trigger Spring initialisation.
FooClass needs to be instancied by Spring to have his depencies managed.
Make sure FooClass is instancied as a bean (#Component or #Service annotation, or XML declaration).
Edit : sessionFactory.setPackagesToScan is looking for JPA/Hibernate annotations whereas #Repository is a Spring Context annotation.
AccountRepositoryImpl should be in the Spring component-scan scope
Regards,

How to initialize List inside Object using Spring Annotation

How do I initialize List inside Object using Spring Annotation
#Component
class Accounts{
private List<Transaction> _transaction;
//getter setter
}
How do I initialize List<Transaction> _transaction; using Spring Annotation or else i
have to define it in xml file.
But i dont want to write any xml file
You can use the Spring Java #Configuration for such a task:
#Configuration
public class SpringConfig {
#Bean
public List<Transaction> transactions() {
...... //Your logic to generate the list..
return transactions;
}
}
And in your Accounts class you have to use #Resource, not #Autowired, the semantics of injecting a list is a little different - if you use #Autowired, any bean of the same type will get injected into the list.
#Component
class Accounts{
#Resource(name="transactions")
private List<Transaction> _transaction;
//getter setter
}
This is pure java solution and there is no xml involved in creating the list..
If Transaction is a Bean with #Service, #Component or #Repository Annotation, you can just write #Autowired on top of your field.
#Component
class Accounts{
#Autowired
private List<Transaction> _transaction;
//getter setter
}

Resources