How to implement DI in Spring MVC.? - java

I have a confusion in Dependency Injection in Spring MVC.
First Code:-
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private Userdao udo;
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}
It is working Fine.
I would like to implement Dependency Injection in this class.Am doing right or wrong?
second code:-
`#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private Userdao udo;
public UserServiceImpl(Userdao udo) {
this.udo = udo;
}
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}
Its not working.ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'homeController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.xxx.Services.UserService com.xxx.java.HomeController.uservice; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl' defined in file [D:\xxxWorkspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\abcd\WEB-INF\classes\com\xxx\ServiceImp\UserServiceImpl.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.xxx.ServiceImp.UserServiceImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.xxx.ServiceImp.UserServiceImpl.<init>()
I am a beginner .please help me to solve this.How to implement DI in Spring MVC.

You can do this two ways.
You can use field based autowiring. But in this case you will need a default constructor.
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired // field based DI
private Userdao udo;
// default constructor
public UserServiceImpl() {}
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}
You can use constructor based dependency injection. To do this simply move your #Autowire annotation to your constructor. And remove it from the field.
#Service
#Transactional
public class UserServiceImpl implements UserService {
private Userdao udo;
#Autowired // constructor based DI
public UserServiceImpl(Userdao udo) {
this.udo = udo;
}
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}

First setup is alright, and should work.
In the second setup you're getting following exception
class [com.xxx.ServiceImp.UserServiceImpl]: No default constructor found;
Which means what it says, since you've defined a constructor public UserServiceImpl(Userdao udo) Spring can't find an no-argument constructor.
You can either remove this constructor and use the first one or you can define the no argument constructor yourself.
You shouldn't actually need to define a constructor in a bean as you're not going to create bean object yourself. You would only need it if you're autorwiring constructor arguments.
If you're trying to autowire constructor then you can do it like below.
#Service
#Transactional
public class UserServiceImpl implements UserService {
private Userdao udo;
#Autowired //autowired constructor, instead of the field
public UserServiceImpl(Userdao udo) {
this.udo = udo;
}
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}

In simple words: If you define a constructor (overloaded) then you must use the #Autowired annotation on the constructor, if you do not define a constructor, then you must use the #Autowired annotation for each Object you need to add as dependency injection. For example:
With constructor overloaded:
#Service
#Transactional
public class UserServiceImpl implements UserService {
private final Userdao userDao;
private final RoleDao roleDao;
#Autowired
public UserServiceImpl(Userdao userDao, RoleDao roleDao) {
this.userDao = userDao;
this.roleDao = roleDao;
}
}
Without constructor overloaded
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private UserDao userDao;
#Autowired
private RoleDao roleDao;
// default constructor
public UserServiceImpl() {}
}
Defining a constructor with a single #Autowired is better than having many objects #Autowired

Related

Autowire a bean requiring another bean for its object creation

I have a class which has following autowiring
public class XYZ {
#Autowired
private Principal principal;
public void main() {
AlexandriaDownloadSignatureUtilityV1 downloadSignatureUtilV1 =
new AlexandriaDownloadSignatureUtilityV1(
getMaterialsetNameProvider(principal),
);
}
}
I want to autowire AlexandriaDownloadSignatureUtilityV1 dependency, but since it is dependent on pricipal bean, can you please tell me how to do so?
#Component
public class XYZ {
#Autowired
private Principal principal;
public void main() {
AlexandriaDownloadSignatureUtilityV1 downloadSignatureUtilV1 =
new AlexandriaDownloadSignatureUtilityV1(
getMaterialsetNameProvider(principal),
);
}
}
Add #Component at the Top of the class this will create a bean of this object and inject their dependency also

SpringBoot - activiti - Injecting org.activiti.engine.TaskService

I've created this class:
public class ActivitiWorkflowService {
private final TaskService taskService;
..
}
but I have this problem when init the project:
No qualifying bean of
type 'org.activiti.engine.TaskService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I expect that your class has a constructor such as:
public class ActivitiWorkflowService {
private final TaskService taskService;
public ActivitiWorkflowService(TaskService taskService) {
this.taskService = taskService;
}
}
The error you are getting is because Spring cannot autowire this class to the ActivitiWorkflowService - it probably was not defined in the Spring context.
Depending on the configuration you use you can either:
Define class with #Component or #Service annotation and let #ComponentScan do its work:
#Component //#Service
public TaskService {
...
}
or if you are using #Configuration class define the bean of type TaskService
#Configuration
public class AppConfig {
#Bean
public TaskService taskService() {
return new TaskService();
}
#Bean
public ActivitiWorkflowService activitiWorkflowService(TaskService taskService) {
return new ActivitiWorkflowService(taskService);
}
}

CDI - #Injected field null

I want to initialize a collection and fill it with data at the startup of my application. Then I would like to access it everywhere in my application. I want for example that my REST API can access the shared collection that is already populated with data.
I first tried to do it with an startup class annotated with #Startup and #Singleton. When I injected my userService in there I had some problems and because of the advice in this post: #Inject and #PostConstruct not working in singleton pattern I tried to do it with an #ApplicationScoped annotation:
#Named
#ApplicationScoped
public class KwetterApp {
#Inject
private UserService service;
#PostConstruct
public void init() {
try {
User harry = new User("Harry", "harry#outlook.com", "New York", "http://harry.com", "Hi, I'm Harry!", UserType.REGULAR);
User nick = new User("Nick", "nick#outlook.com", "California", "http://nick.com", "Hi, I'm Nick!", UserType.REGULAR);
User jane = new User("Jane", "jane#outlook.com", "Texas", "http://jane.com", "Hi, I'm Jane!", UserType.REGULAR);
Tweet tweet = new Tweet("eating...", harry);
Tweet tweet1 = new Tweet("swimming...", harry);
Tweet tweet2 = new Tweet("jogging...", jane);
harry.addTweet(tweet);
harry.addTweet(tweet1);
jane.addTweet(tweet2);
service.create(harry);
service.create(nick);
service.create(jane);
}
catch (Exception e){
e.printStackTrace();
}
}
public UserService getService() {
return service;
}
}
I inject this class in my rest service:
#RequestScoped
#Path("/user")
public class UserRest {
// #Inject
// private UserService userService;
#Inject
private KwetterApp kwetterApp;
// private KwetterApp kwetterApp = KwetterApp.getInstance();
private UserService userService = kwetterApp.getService();
#GET
#Produces({"application/json"})
public List<User> get() throws UserException {
return userService.getAll();
}
}
When injecting this KwetterApp it leads to the following exception:
StandardWrapperValve[rest.RestApplication]: Servlet.service() for servlet rest.RestApplication threw exception
java.lang.NullPointerException
at rest.UserRest.<init>(UserRest.java:27)
at rest.UserRest$Proxy$_$$_WeldClientProxy.<init>(Unknown Source)
I have an empty beans.xml file with bean-discovery-mode set to 'all'. The CDI framework should recognize my KwetterApp class for injection, right? Why is it null?
Thanks in advance,
Mike
Here
#Inject
private KwetterApp kwetterApp;
private UserService userService = kwetterApp.getService();
I do not think the kwetterApp field is going to be set before userService.
CDI will set that field after the object has been constructed.
An alternative, which should be used anyway, is constructor injection
#RequestScoped
#Path("/user")
public class UserRest {
private KwetterApp kwetterApp;
private UserService userService;
protected UserRest() {}
#Inject
public UserRest(final KwetterApp kwetterApp) {
this.kwetterApp = kwetterApp;
this.userService = kwetterApp.getService();
}
#GET
#Produces({"application/json"})
#Override
public List<User> get() throws UserException {
return userService.getAll();
}
}
A protected constructor is needed because #RequestScoped is a normal-scoped bean, and it must be proxiable, as described in the specification.
The only annotation that doesn't require an empty constructor is #Singleton (from javax.inject).
If you want to initialize an object by using an injected bean, then you have to use a #PostConstruct annotated method, because injected CDI beans are only available in CDI in a #PostContruct annotated method and afterwards and not during field initialization or the constructor invocation.
Therefore that the UserService is a CDI bean already, you can just inject it into your rest service bean, because it will be the same bean used within the current active scope. KwetterApp is available within the current active scope, so UserService will be as well. Only #Dependend scoped beans behave different, whereby each bean gets its own instance provided.

What is the difference between using #Qualifier annotation and directly injecting bean in spring?

Suppose I have a program
#Component
public interface Coach{
public String giveCoaching();
}
#Component
public TennisCoach implements Coach{
#Override
public String giveCoaching(){
return "Teaching forhand";
}
}
I have two Demo classes in which I have injected the bean in different ways. what is the difference in both the injections
public class AppDemo{
#AutoWired
#Qualifier("tennisCoach")
private Coach theCoach;
}
public class AppDemo{
#AutoWired
private TennisCoach tennisCoach;
}
}
When you have more than 1 implementation for you interface, you will get an exception when Autowiring the bean. At that time #Qualifier will be used to choose the required implementation
#Component
public interface Coach{
public String giveCoaching();
}
#Component
public TennisCoach implements Coach{
#Override
public String giveCoaching(){
return "Teaching forhand";
}
}
#Component
public CricketCoach implements Coach{
#Override
public String giveCoaching(){
return "Teaching forbat";
}
}
Now the ambiguity will occur when you autowire the Coach Interface like below
public class AppDemo{
#AutoWired
private Coach theCoach;
}
So you have to qualify the right bean for the CoachInterface like below.
public class AppDemo{
#AutoWired
#Qualifier("tennisCoach")
private Coach theCoach;
}
Alternatively you can use #Primary annotation on top of any one of the implementation so that the Spring Container will by default choose the bean in case of more than 1 implementation for an interface.
But in the code below, you are directly creating the object for the implementation rather than interface.
public class AppDemo{
#AutoWired
private TennisCoach tennisCoach;
}
}
#Qualifier annotation is used when your interface has more than one implementing class, You should opt for the one you want inject as a bean in spring context.

spring variable injection from an autowired object

I have a class like this -
#Service
public class SomeClass {
#Autowired
Environment env;
private String property;
#Value("${pty}")
public void setPty(String pty) {
pty = environment.getProperty("pty");
}
}
I'm trying to inject the 'pty' variable from another class 'Environment' which is autowired and I get this exception when my server startups
Error creating bean with name 'someClass': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire method: public void
service.facade.ActionFacade.setPty(java.lang.String);
nested exception is java.lang.IllegalArgumentException: Could not
resolve placeholder 'pty' in string value "${pty}"
The exception is because there is no property pty in your Spring context. #Value lookup the placeholder 'pty' in the resource files loaded.
In your case it is not required as you need to get it from Environment class which you have Autowired already, below code will give you the idea.
#Service
public class SomeClass {
#Autowired
Environment env;
private String property;
#PostConstruct
public void init(){
property=env.getProperty("pty");
}
}
Try #PostConstruct
The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization.
#PostConstruct
public void init() {
property = env.getProperty("pty");
}
You can do this with the help of Spring bean life cycles:
1. InitializingBean -> afterPropertiesSet
2. #PostConstruct
public class EmployeeService implements InitializingBean{
private Employee employee;
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
#PostConstruct
public void init() {
property = env.getProperty("pty");
}
#Override
public void afterPropertiesSet() throws Exception {
}
}

Categories

Resources