#AllArgsConstructor and Constructor Injection with Spring: is private final needed? - spring-boot

Let's say I have the following constructor injection (not Autowiring):
#Service
public class FooService {
private final OrderService orderService;
public FooService(OrderService orderService) {
this.orderService = orderService;
}
}
That can be replaced with:
#Service
#AllArgsConstructor
public class FooService {
private final OrderService orderService;
}
Do I need to declare this as private and final to inject this service? Does Lombok take care of this like they do with #Data and beans? Any side-effects?

You should use #RequiredArgsConstructor instead, you need a single primary constructor to fill the required fields. So you marked them final and use this annotation to generate a primary constructor.
#AllArgsConstructor is bug-prone, because it may produce multiple constructors which Spring may fail to handle.
In your particular case the results of #AllArgsConstructor and #RequiredArgsConstructor just happen to be the same, because you have just one final field.
Note that, Spring documentation encourages the usage of constructor-based injection (https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-setter-injection), and recommends to avoid using several injection techniques together.
#Service
#RequiredArgsConstructor
public class FooService {
private final OrderService orderService;
}

According to documentation
#AllArgsConstructor generates a constructor with 1 parameter for each field in your class. Fields marked with #NonNull result in null checks on those parameters.
So, no, it does not make your fields private & final as for example #Value annotation.

Related

#Autowire on field vs #Autowired on Construcor

I am developing a SpringBoot application. Can anyone help me understand what is the difference between the below piece of code. I am working on a restful service and I saw constructor being autowired. I can understand its Constructor Injection. Usually I autowire a field. So I am unable to understand the difference between two.
Scenario 1:
#RestController
public class SomeServiceController {
#Autowired
private ASerice aService;
#Autowired
private BService bService;
}
Scenario 2:
#RestController
public class SomeServiceController {
private ASerice aService;
private BService bService;
#Autowired
public SomeServiceController (AService aService, BService bService)
{
this.aService = aService;
this.bService = bService;
}
}
The difference is that with the constructor injection, the class SomeServiceController can only be created if with this constructor.
So you could even instantiate the class to test it.
With field injection, this is not possible. To instantiate the class for a test, you must use reflection to set the two private services.
It's highly recommended to use constructor expression.
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-collaborators

How to use unit of work in rest controller properly?

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;
}

Different behaviour of injected fields in unit test and deployed version

I am new in lombok and spring and I have one issue which I am trying to understand. Firstly my code was design as below and then I modified it because I needed to have a setter.After that all tests passed. But after deployment I started to get null pointer exception for the service field.
So my question is why I am getting null pointer exception? I think after removing final keyword lombok does not create constructor for that field. But still I do not understand why it did not fail on unit tests if that is the reason? And what is the solution for it ?
This is the first version which works.
#Component
#RequiredArgsConstructor
public class MyClass{
private final MyServiceservice service;
private final MyOtherService otherservice;
}
This the version after update and where service field is null.
#Component
#RequiredArgsConstructor
public class MyClass{
#Setter
private MyServiceservice service;
private final MyOtherService otherservice;
}

Autowiring of Service and Service Implementation class

Following are my code
#RestController
public class EmployeeController {
#Autowired
EmployeeService empService;
public EmployeeController (EmployeeService Impl empServiceImpl) {
super();
this.empService = empServiceImpl;
}
}
#Service
public interface EmployeeService {
public List<EmployeeDTO> getAllEmployeeDetails()
}
public class EmployeeServiceImpl {
public List<EmployeeDTO> getAllEmployeeDetails(){
//methods business logic and repo call goes here
}
}
When I start my server I am getting below error.
Parameter 1 of constructor in
com.app.in.controller.EmployeeController required a bean of type
'com.app.in.service.EmployeeServiceImpl' that could not be found
My understanding might be wrong. If I annotate the EmployeeSeriveImpl class also with #Service then it working.Is that is the correct way to do it ? My question is the service interface is annotated with #Service still why its implementation is also required to annotation. Please let me know if I miss something in that ? What is the standard method to solve this issue ?
You can get your dependency injected using a constructor. And #Autowired is optional in this case.
This is your example, but with a few corrections:
#RestController
public class EmployeeController {
// private final is a good practice. no need in #Autowire
private final EmployeeService empService;
// this constructor will be used to inject your dependency
// #Autowired is optional in this case, but you can put it here
public EmployeeController (EmployeeService empServiceImpl) {
this.empService = empServiceImpl;
}
}
I assume you have an interface EmployeeService and class EmployeeServiceImpl which implements that interface and is Spring Bean.
Something like this:
#Service
public class EmployeeServiceImpl implements EmployeeService {}
Why this #Service is needed? When you put this annotation on your class, Spring knows this is a bean that Spring should manage for you (container will create an instance of it and inject it wherever it is needed).
Check Spring docs to get more details about Dependency Injection.
The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null.

Autowired is null in Spring

I have a class TestServiceImpl which is annoted with #Service and #EnabledTransactionManagement annotation.
I am refering 2 DAO objects in it #Autowired Service1DAO s1 and #Autowired Service2DAO s2. The Service1DAO and Service2DAO classes are annoted with #Repository annotation.
The methods are annoted with #Trasanction and required parameters according to requirement.
The questio is:
I am able to get s1 object but when I am trying to get the s2 object it is showing me null.
They are defined one by another.
The serivie class is:
#Service
#Scope("prototype")
#EnabledTransactionManagement
public class TestServiceImpl {
#Autowired Service1DAO s1;
#Autowired Service2DAO s2;
#Transation(readOnly = false, propogation = Propagation.REQUIRED_NEW)
public String getXXX1(){
s1.print();
}
#Trsanction(readOnly = false, propogation = Propagation.REQUIRED_NEW)`enter code here`
public String getXXX2(){
s2.write();
}
}
DAO classes are:
#Repository
public class Service1DAO implements Service1{
#PersistentContext
EntityManager em;
public String Print(){
em.XXXXXX();
}
}
#Repository
public class Service2DAO implements Service2{
#PersistentContext
EntityManager em;
public String write(){
em.XXXXXX();
}
}
The xml contains the component scan pakcage mentioned.
Ok ... The error has been resolved.
The Service class object created in controller using new() and I was looking those in service and dao classes. It was mistake related to code implementation, even using Spring still follow the path of java to create a object.

Resources