This is my current scenario:
#WebListener
public class WebListenerService implements HttpSessionListener{
.... implement methods
#Produces
#Dependent
public SessionDependentService sessionDependentService(){
}
}
#SessionScoped
#Named
public class AccountController implements Serializable{
//Injected properly and works as expected
#Inject
private SessionDependnetService sessionDependentService;
#Inject
#OnLogin
private Event<Account> accountEvent;
public void onLogin(){
accountEvent.fire(authenticatedAccount);
}
}
#SessionScoped
public class AccountObserver implements Serializable{
//This does not work. It is always null.
#Inject
private SessionDependnetService sessionDependentService;
public void onLoginEvent(#Observes #OnLogin final Account account) {
//When this methods is invoked
//the sessiondependentservice is always null here.
}
}
In the AccountController, the SessionDependentService is correctly injected and is not null, while in the AccountObserver, it is always null.
EDIT:
Event using the parameter injection still results to a null value.
public void onLoginEvent(#Observes #OnLogin final Account account, final SessionDependnetService sessionDependentService) {
//When this methods is invoked
//the sessiondependentservice is always null here.
}
Netbeans correctly highlights this as an injection point.
Why is this the case?
I am using wildfly 8 server.
I changed the producer bean from SessionScoped to Stateless bean:
#Stateless
public class WebListenerSessionService {
//Use Instance since http session are dynamic.
#Inject
private Instance<HttpSession> httpSession;
#Produces
#Dependent
public SessionDependentService sessionDependentService(){
//use session to lookup existing service or produce a new one.
}
}
Even though this works fine, there is no where in the CDI spec which says Producer method must be session beans.
to quote:
A producer method must be a default-access, public, protected or private, non-abstract method
of a managed bean class or session bean class. A producer method may be either static or non-
static. If the bean is a session bean, the producer method must be either a business method of
the EJB or a static method of the bean class.
And since #SessionScoped is a managed bean class, why would it an injection into an observer bean not work.
Related
I'm relatively new to Spring, and I'm trying to understand an issue I'm experiencing in which a dependency is not being autowired into a bean that is the parent of another bean that is being constructed.
The parent class is specified as follows. Note that I've abbreviated some of the logic for clarity. The Log class is implemented as an entity.
#Component
#Scope("prototype")
public class AppTransaction {
private String componentName;
#Autowired
private LogRepository logRepository;
public AppTransaction(String componentName) {
this.componentName = componentName;
}
public void writeLog(String logText) {
Log log = new Log(this.componentName, logText);
this.logRepository.save(log);
}
}
The child class is implemented as follows.
#Component
#Scope("prototype")
public class EmployeeJobTransaction extends AppTransaction {
#Autowired
private EmployeeRepository employeeRepository;
private String componentName;
private String jobName;
public EmployeeJobTransaction(String componentName, String jobName) {
super(componentName);
this.jobName = jobName;
}
public List<String> doJob() {
List<String> statuses = this.employeeRepository.getEmployeeJobStatuses();
writeLog("Job complete.");
}
}
In my service class, I'm using the application context to get an instance of the EmployeeJobTransaction bean. I'm doing this because the input parameters to the EmployeeJobTransaction bean are based on user input.
#Service
public class JobServiceImpl {
#Autowired
private ApplicationContext applicationContext;
public void initJob() {
EmployeeJobTransaction employeeJobTransaction = this.applicationContext.getBean(EmployeeJobTransaction.class, "EmployeeComponent", "CheckEmployeeJobStatus");
jobTransaction.doJob();
}
}
When I get the EmployeeJobTransaction bean, the EmployeeRepository bean is autowired as expected. However, the AppTransaction instance created does not appear to be a Spring-managed bean because the LogRepository object that has been autowired is null. I'm assuming this is because the call to super() in the EmployeeJobTransaction class does not create an instance of AppTransaction as a Spring-managed bean.
What are my options? Must I autowire the LogRepository bean into the EmployeeJobTransaction class and then pass it to the writeLog method as a parameter? I'm not understanding why the parent class is not created as a Spring bean when the child class is created as such.
For those that may come across this question in the future, I understand now that I was interpreting what Spring was doing incorrectly.
I turned on debugging and had set a breakpoint in the AppTransaction constructor.
public AppTransaction(String componentName) {
this.componentName = componentName; //Breakpoint here
}
When I executed my logic, I was confused because the autowired LogRepository bean was null.
According to the Spring documentation:
Fields are injected right after construction of a bean, before any config methods are invoked.
Therefore, it makes sense that the LogRepository bean is null in the constructor. When the writeLog method is called, the LogRepository bean is not null because it was successfully autowired AFTER the construction of the AppTransaction bean.
Thanks to those who responded.
TLDR: Autowired fields are null inside the constructor of a bean. The beans are not autowired until the construction of the bean in which they are referenced has completed.
I think you are a littel confused. I will try to explain me:
Your code shows 3 Spring beans:
AppTransaction
With an autowired dependency of the logRepository
EmployeeJobTransaction
With an autowired dependency of the employeeRepository
With an autowired dependency of the logRepository (inhereted of the parent class AppTransaction)
JobServiceImpl
When you call to he super method on EmployeeJobTransaction you are not calling to AppTransaction bean. You are calling to the parent class constructor method.
Is unnecessary to have a Spring bean of the AppTransaction class (remove the Component and Scope annotations of this class)
When you call to getBean method, Spring create a new bean each time. I think this is unnecessary. You could declare EmployeeJobTransaction bean as singleton (remove de Scope annotation) and to add the componentName and jobName attributes as parameters of doJob method.
I think woult be the best way.
Consider the following classes:
#Component
#Scope(scopeName = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
class PrototypeBean
{
public void method1() { ... };
public void method2() { ... };
}
#Component
public class SingletonBean
{
#Autowired
private PrototypeBean prototypeBean;
public void SingletonBean doSomething()
{
prototypeBean.method1();
prototypeBean.method2();
}
}
Now, I would expect that everytime doSomething() method is called, a new PrototypeBean instance is created and injected to SingletonBean.
But what really happens is a new PrototypeBean instance is created and injected into SingletonBean when I call method1() and method2().
I don't really get why, this should've worked as far is I'm concerned.
Please correct my if I'm wrong.
Yes, That is expected !!
Because you declared the bean's scope attribute as prototype #Scope(scopeName = "prototype")that force the Spring IoC container creates a new bean instance of the object every time a request for that specific bean is made.
Note:As a rule, use the prototype scope for all state-full beans and the singleton scope for stateless beans.
Yes that is expected since beans are only initialized on demand, for prototype scope the bean will be initialized each time it is needed.
I'm having trouble getting #Autowired to work in a class annotated by #Service, the autowired variable always is null. Let me explain:
#Service
public class Searcher extends Thread implements ISearcher {
#Autowired
protected ISessionProvider sessionProvider; <-- always null
...
public Searcher() {
sessionProvider.doSomeStuff();
}
sessionProvider here is always null.
The strange thing is that the same autowire in a #Controller does work:
#Controller
#RequestMapping("/search")
#Secured({ "ROLE_USER" })
public class SearchController extends BaseController {
#Autowired
protected ISessionProvider sessionProvider; <-- does work
#Autowired
protected ISearcher searcher;
The last line throws exception because the constructor of Searcher (implementing ISearcher) tries to access sessionProvider, which is null.
I am not sure what i might be doing wrong, it looks like spring doesn't autowire the ISessionProvider in Searcher.
It might be that spring first autowires the Searcher in SearchController, but it should first autowire SessionProvider in Searcher and next autowire Searcher in SearchController. Cause searcher cannot be autowired without a valid SessionProvider. Puzzles my brain ;-)
Can somebody offer a helping brain?
[edit]
component-scan includes my services, controllers and everything, just checked.
the I before interfaces is indeed not very nice (old habits)
not sure if this is a "duplicate" question, mainly because i'm not doing anything with "new", i let do spring do all the hard work, but i'll take a better peek.
Spring will first create the bean instance, then inject the beans. You're trying to access to the injected bean when the current bean is created, thus the bean will be null. That's default behavior.
If you want/need to execute any logic after creating the bean, use #PostConstruct decorated method, which is invoked after the bean has been created and all the dependencies injected. Here's a sample:
#Service
public class Searcher extends Thread implements ISearcher {
#Autowired
protected ISessionProvider sessionProvider;
public Searcher() {
//nothing should be here...
}
#PostConstruct
public void init() {
sessionProvider.doSomeStuff();
}
}
Spring can only do dependeny injection after the bean has been constructed. You are calling the method in the constructor and at that point the ISessionProvider hasn't been injected yet and hence it is null which in turn leads to a nice NullPointerException.
You have 2 solutions
Move the code from the constructor to a method annotated with #PostConstruct
Change the default no-arg constructor to take an argument and use that to do dependeny injection instead of the #Autowired field.
Solution 1: move that code to a method annotated with #PostConstruct.
#Service
public class Searcher extends Thread implements ISearcher {
#Autowired
protected ISessionProvider sessionProvider;
...
public Searcher() {}
#PostConstruct
public void init() {
sessionProvider.doSomeStuff();
}
Solution 2: Use constructor based dependency injection.
#Service
public class Searcher extends Thread implements ISearcher {
protected final ISessionProvider sessionProvider;
#Autowired
public Searcher(ISessionProvider sessionProvider) {
this.sessionProvider=sessionProvider;
sessionProvider.doSomeStuff();
}
}
I didn't do test, but I think the problem is, in class Searcher, you created a no-argument constructor, and there you used the "autowired" bean. I guess there you would get NPE. Since spring would instantiate your Searcher using default constructor (by reflection) if you didn't specify one, that is, it will use the no-argument constructor you created, but at this moment, the "autowired" bean was not yet injected.
If you want to do something immediately after the bean was instantiated, you can wrap the logic code in a method, and annotate it with #PostConstruct.
I am also getting the same issue but i cannot use #PostConstruct because i am not using doinit. I have a simple method which is getting the language from lang service.
My lang service is null here but in another controller it is not null, it is getting autowired.
#Service
#Configurable(preConstruction = true, autowire = Autowire.BY_NAME)
public class FormSelectLanguageHandler extends SimpleTagSupport {
#Autowired
private LangService langService;
public List<Lang> getLanguages(){
Sessions session = (Sessions) getJspContext().findAttribute("SHLSESSION");
List<Lang> languages=new ArrayList<Lang>();
//List<Lang> allLanguages = langService.findAllLangs();
List<Lang> all =new ArrayList<Lang>();
if (isRenderLangLabel()) {
all = langService.findByDisplayOrderAsc();
} else {
all = langService.findByNameOrderByNameAsc();
}
Long companyId = (null == session || null == session.getCompany())? null:session.getCompany().getId();
}
}
I have a scenario where autowired is null when called in the constructor of an abstract class like this :
public abstract class AbstractClass{
#Autowired
#Qualifier("proId")
protected Prop prop;
public AbstractClass(){
prop.getName();
The above throws NullException on deployment.
But the following works when the autowired property called after instantiating
public abstract class AbstractClass{
#Autowired
#Qualifier("proId")
protected Prop prop;
public void Init(){
prop.getName();
}
}
public class DefaultClass extends AbstractClass(){
...
#autowired
DefaultClass dc ;
...
dc.Init();
How can I get the first case to work ?
You can't. Injection can only happen after an object has been created (or during construction with constructor injection). In other words, when prop.getName() is called inside the abstract class constructor, the field is still null since Spring hasn't processed it.
Consider refactoring your code so that your abstract class has a constructor that accepts a Prop argument and use constructor injection
public AbstractClass(Prop prop) {
this.prop = prop;
prop.getName();
}
...
#Autowired
public DefaultClass(Prop prop) {
super(prop);
}
Do you know object creation life-cycle in Java?
Spring doesn't do any magic about that.
There are multiple phases when using Spring for creating beans
an object is instantiated using the constructor
dependencies are injected into bean (obviously except for constructor dependencies which are passed through the object in first phase)
objects #PostConstruct (or InitializingBean) methods are called.
Remember that before constructor there is no instance of your bean, so Spring can not wire anything in it!
I have a Bean ,with a #ManagedBean annotation, defined like this :
#ManagedBean
#SessionScoped
public class Bean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
}
Now, I have another bean defined like this :
public class FooBean extends Bean {
// properties, methods here ...
}
When I try to reference FooBean in my JSF page, I have the following error :
Target Unreachable, identifier 'fooBean' resolved to null
Why JSF doesn't see FooBean as a managed bean ?
The point Alex is trying to make is that you're confusing classes with instances. This is a classic (pun intended) OOP mistake.
The #ManagedBean annotation does not work on classes per-se. It works on instances of such classes, defining an instance that is managed.
If your bean is defined like this:
#ManagedBean
#SessionScoped
public class MyBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
}
Then it means you have a session-scoped instance, called myBean (or whatever you want to name it).
Therefore, all classes that are subclasses of the MyBean class are not managed by default. Furthermore, how does JSF recognize where you're using the subclasses? If so, what names are you giving to those instances? (Because you have to give them some name, otherwise, how would JSF manage them?)
So, let's say you have another class:
Class MyOtherClass {
private MyBean myBeanObject; // myBeanObject isn't managed.
}
what happens to the #PostConstruct and all the other annotations you used? Nothing. If you created the instance of MyBean, then it's YOU who manages it, not JavaServerFaces. So it's not really a managed bean, just a common object that you use.
However, things change completely when you do this:
#ManagedBean
#SessionScoped
Class MyOtherClassBean {
#ManagedProperty("#{myBean}")
private MyBean myBeanObject;
public void setMyBeanObject(...) { ... }
public MyBeanClass getMyBeanObject() { ... }
}
Then again, what is managed is not the class, but the instance of the class. Having a ManagedBean means that you only have one instance of that bean (per scope, that is).
do you need BaseBean to be a managed bean? Since you name it BaseBean, I assume that this bean hold commonality between all your other managed bean. If so then it should not contain #ManagedBean annotation. Do this
public abstract BaseBean{
//...
}
Then inside your managed bean
#ManagedBean
#RequestScoped
public class FooBean extends BaseBean{
//...
}