#Inject-ed value null in #FacesComponent - jsf

I have the impression that CDI is not working with classes that have a #javax.faces.component.FacesComponent. Is this true?
Here's my example, that doesn't work. The MyInjectableClass is used at other points in the code where injection is not a problem, so it must be about the #FacesComponent annotation I think.
The class I want to inject:
#Named
#Stateful
public class MyInjectableClass implements Serializable {
private static final long serialVersionUID = 4556482219775071397L;
}
The component which uses that class;
#FacesComponent(value = "mycomponents.mytag")
public class MyComponent extends UIComponentBase implements Serializable {
private static final long serialVersionUID = -5656806814384095309L;
#Inject
protected MyInjectableClass injectedInstance;
#Override
public void encodeBegin(FacesContext context) throws IOException {
/* injectedInstance is null here */
}
}

Unfortunately, even for JSF 2.2 #FacesComponent, #FacesValidator and #FacesConverter are not valid injection targets (read What's new in JSF 2.2? by Arjan Tijms for more details). As Arjan points out:
It’s likely that those will be taken into consideration for JSF 2.3 though.
What can you do for now? Well, you've got basically two choices:
Handle CDI injection via lookup, or switch to EJB and do the simpler EJB lookup;
Annotate tour class with #Named instead of #FacesComponent, #Inject the component the way you did and register your component in faces-config.xml. As the UI component instance is created via JSF Application#createComponent(), not via CDI you will also need a custom Application implementation as well (exactly like OmniFaces has for those converters/validators).
And, by the way, you've got two issues with what you've got this far: (1) what is meant by #Named #Stateful when the former is from a CDI world and the latter is from EJB world and (2) are you sure you intend to keep state in a faces component that's basically recreated on every request?

#FacesCompnent is managed by JSF and injection is not supported into them.

Passing the value in from the XHTML page via a composite component attribute worked for us.

Related

Getting application scoped bean in JSF 2.2 custom component

I am developing a new JSF 2.2 application.
I have an eagerly created, application scope managed bean that loads up some configuration data from an external file, at startup, and stores it as state.
I have a FacesComponent and FacesRenderer that I have working statically.
I would like to be able to get the configuration data stored in the managed bean into the FacesComponent. Is there a standard way to do this.
As far as I am aware, the managed bean cannot be injected into the component - is that correct?
I can try to get data into the custom component using attributes and el in the .xhtml file that uses the custom component e.g.
<my:customComponent data="#{managedBean.loadedData}"/>
but this seems like a really backwards way to do things and actually exposes internal implementation of the component to the component user.
Please let me know if there is another way, or if you need any more information.
Update: #BalsusC I have tried what you suggested
I have a loader that puts the loaded data into a holder object
#Named
#ApplicationScoped
public class Loader implements Serializable {
#Inject
private Holder holder
#PostConstruct
public void init() {
// Load data into the holder here
}
}
The holder is another application scoped bean
#Named
#ApplicationScope
public class Holder {...}
When loading the data the Holder instance is injected correctly into the Loader.
However when I they the following
#Named //Makes no difference if this is here or not
#FacesComponent(value="family", createTag=true, namespace="...namespace...", tagName="tag")
public class Component extends UIComponentBase {
#Inject
public class Holder holder;
#Override
public void encodeBegin(FacesContext context) {
holder.getData();
}
}
when the component comes to render, the holder is not injected and I get a null pointer exception. I have tried to do this with our without the #Named annotation with the same result.
Am I doing something wrong? Can you please advise.
Application scoped JSF managed beans are internally stored in the application map with the managed bean name as key.
So, the below inside any of UIComponent methods should do:
ManagedBean managedBean = (ManagedBean) getFacesContext().getExternalContext()
.getApplicationMap().get("managedBean");
// ...
This only makes the component tight coupled to the managed bean. I.e. the component can't exist without the managed bean. This should be clearly documented if the component is intented to be reusable in other webapps. Another option is to tie the managed bean exclusively to the component (perhaps in form of a composite component) and use another application scoped bean for "unrelated" application data.

Injecting ResourceBundle via #ManagedProperty doesn't seem to work inside #Named

How can I access messages bundle from java code to get message according to current locale?
I tried using #ManagedProperty like below:
#Named
#SessionScoped
public class UserBean implements Serializable {
#ManagedProperty("#{msg}")
private ResourceBundle bundle;
// ...
public void setBundle(ResourceBundle bundle) {
this.bundle = bundle;
}
}
However, it remains null. It seems that it doesn't work inside a #Named.
This is how I registered the resource bundle in faces-context.xml:
<application>
<message-bundle>validator.messages</message-bundle>
<locale-config>
<supported-locale>en_US</supported-locale>
<supported-locale>ua_UA</supported-locale>
</locale-config>
<resource-bundle>
<base-name>lang.messages</base-name>
<var>msg</var>
</resource-bundle>
</application>
updated by author:
I get error
16:29:10,968 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/WEBSearchPrime_JB_lang].[Faces Servlet]] (http-localhost-127.0.0.1-8080-1) Servlet.service() for servlet Faces Servlet threw exception: org.jboss.weld.exceptions.IllegalProductException: WELD-000054 Producers cannot produce non-serializable instances for injection into non-transient fields of passivating beans\\n\\nProducer\: Producer Method [PropertyResourceBundle] with qualifiers [#Any #Default] declared as [[method] #Produces public util.BundleProducer.getBundle()]\\nInjection Point\: [field] #Inject private model.UserBean.bundle
note, that I also put Serializable interface
You can't use #javax.faces.bean.ManagedProperty in a CDI managed bean as annotated with #Named. You can only use it in a JSF managed bean as annotated with #ManagedBean.
You need use #javax.faces.annotation.ManagedProperty instead, along with an #Inject. This was introduced in JSF 2.3.
#Inject #javax.faces.annotation.ManagedProperty("#{msg}")
private ResourceBundle bundle;
Noted should be that this gets injected as a #Dependent. So be aware that when you inject this into a #SessionScoped bean, then it would basically become #SessionScoped too and thus stick to the originally injected value forever. So any potential locale changes later on in the session won't be reflected there. If this is a blocker, then you should really inject it into a #RequestScoped or #ViewScoped only, or make use of a #Producer as shown below.
CDI doesn't have native annotations to inject the evaluation result of an EL expression. The CDI approach is using a "CDI producer" with #Produces wherein you return the concrete type, which is PropertyResourceBundle in case of .properties file based resource bundles.
So, if you cannot upgrade to JSF 2.3, then just drop this class somewhere in your WAR:
#RequestScoped
public class BundleProducer {
#Produces
public PropertyResourceBundle getBundle() {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().evaluateExpressionGet(context, "#{msg}", PropertyResourceBundle.class);
}
}
With this, can inject it as below:
#Inject
private PropertyResourceBundle bundle;
In addition to BalusC's answer:
Since JSF 2.3 it is also possible to inject a resource bundle defined in faces-config.xml without the use of a producer method. There is a new annotation javax.faces.annotation.ManagedProperty (note it is in the ...annotation package, not the ...bean package) that works with #Inject:
// ...
import javax.faces.annotation.ManagedProperty;
// ...
#Named
#SessionScoped
public class UserBean implements Serializable {
// ...
#Inject
#ManagedProperty("#{msg}")
private ResourceBundle bundle;
// ...
}
Perhaps I'm getting something wrong, but actually neither of the solutions provided worked for my use case. So I'm providing another answer that worked for me.
With the answer provided by BalusC I encountered the following problems:
As I'm using ajaxbased validation, my beans are #ViewScoped, and
must be serializable. As neither ResourceBundle nor
PropertyResourceBundle are serializable they can't be injected with
#Dependent scope.
If I try to change the producer to use #RequestScoped it also fails
because ResourceBundle is not proxyable as it defines final
methods.
As I'm using JSF 2.3 (JBoss 7.2EAP) I went with the solution provided by Jören Haag and initially it seemed to work. Like the original question, I also have multiple supported locales, and the user can change between locales (in my case ca and es)
The problems I faced with Jören answer are
The ResourceBundle returned is evaluated when the bean is created. In his example he is using a #SessionScoped bean. The ResourceBundle will be resolved with the current locale when the session is created. If the user later changes the locale, the ResourceBundle will not get updated. This also happens with #ViewScoped beans if the user can change the language without changing the view.
I also encountered another issue with beans that need to preload data with a <f:viewAction>. In this case, the bean is instantiated earlier, so the ResourceBundle gets injected before the user locale is set with <f:view locale="#{sessionBean.locale}">. So If the user browser is using es, but the user changed the locale to ca, the bundle will be loaded with es instead, because the view locale is not set to ca with the sessionBean.locale until the render phase.
To overcome this issues that's the solution that worked for me for the use case of the question using injection would be:
#SessionScoped
public class UserBean implements Serializable {
#Inject
#ManagedProperty("#{msg}")
private Instance<ResourceBundle> bundle;
// ....
public void someAction() {
String message = bundle.get().getString("someLabel");
// ...
}
}
As the original question doesn't require injection, only asks how to access a resource bundle with the current locale, a solution without injection, and without the overhead of evaluating EL expression #{msg} every time bundle.get() is called would be:
#SessionScoped
public class UserBean implements Serializable {
#Inject
private FacesContext context;
// ...
public void someAction() {
ResourceBundle bundle = context.getApplication().getResourceBundle(context, "msg");
String message = bundle.getString("someLabel");
// ...
}
}

What makes a bean a CDI bean?

In the top answer to this question for example : Java EE 6 #javax.annotation.ManagedBean vs. #javax.inject.Named vs. #javax.faces.ManagedBean I read that:
To deploy CDI beans, you must place a file called beans.xml in a
META-INF folder on the classpath. Once you do this, then every bean in
the package becomes a CDI bean.
And also it is said that:
If you want to use the CDI bean from a JSF page, you can give it a
name using the javax.inject.Named annotation.
I have a sample code that goes like this:
#ManagedBean
#ViewScoped
public class SignUpPage {
private User user;
#PostConstruct
public void init() {
user = new User();
}
#Inject
private UserDao userDao;
// rest of the class
So as far as I understand, my bean is still a JSF Managed Bean, it is not a CDI bean(or is it?). By the way, I have a beans.xml in my WEB-INF folder.
And #Inject works just fine in here. Also, I can access the bean with EL just fine(which makes me think it is still a JSF Managed Bean)
The UserDao class looks something like this:
#Stateless
public class UserDao {
EntityManager em;
#PostConstruct
public void initialize(){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Persistence");
em = emf.createEntityManager();
}
So, it is as far as I know an EJB..
So do I have any CDI beans in this example? How does #Inject work here?
Hope my question is clear, Regards!
By CDI specification, every JavaBean is a Managed Bean (do not confuse it with JSF #ManagedBean, this is a different one) in project where the beans.xml is present. So every class is also eligible for dependency injection. Note that default scope of this class is Dependent.

Inject Bean that uses #Named with value

how can I Inject a Bean, that uses a #Named annotation along with a value?
#Named
public class LanguageService{
...
}
public class SomeOtherBean{
#Inject
private LanguageService languageService
}
works without Problem - but how to inject, if i'm using:
#Named("lang")
public class LanguageService{
...
}
#Inject can't have a value as #ManagedProperty does. (But I wan't to stay with CDI)
Edit:
I noticed that it doesn't matter how the bean is named. My Fault that leads to an NPE was simple that i created SomeOtherBean manually, and ofc. no Injection was done. My fault.
CDI selects injectable beans by type (and qualifiers) and not by the annotation parameter. The name is used to address a CDI bean from views, e.g. facelets.

Inject a EJB into a JSF converter with JEE6 [duplicate]

This question already has answers here:
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
(5 answers)
Closed 6 years ago.
I have a stateless EJB that acceses my database.
I need this bean in a JSF 2 converter to retreive an entity object from the String value parameter. I'm using JEE6 with Glassfish V3.
#EJB annotation does not work and gets a NPE, because it's in the faces context and it has not access to the EJB context.
My question is:
Is it still possible to Inject this bean with a #Resource or other annotation, or a JNDI lookup, or do I need a workaround?
Solution
Do a JNDI lookup like this:
try {
ic = new InitialContext();
myejb= (MyEJB) ic
.lookup("java:global/xxxx/MyEJB");
} catch (NamingException e) {
e.printStackTrace();
}
I never used JSF 2.0 (only 1.0), but chapter 5.4 of the spec says:
[...] allow the container to inject references to
container managed resources into a managed bean instance before it is made accessible to the JSF application.
Only beans declared to be in request,
session, or application scope are
eligble for resource injection.
But so far I understand, a JNDI lookup should do the trick.
Other (yet not so pretty) solution may be using binding instead of converterId. Using JSF managed beans only:
<f:converter binding="#{app.personConverter}" />
Where appBean stands for something like:
#ManagedBean(name="app")
#ApplicationScoped
class AppBean {
#EJB
private PersonService ps;
private Converter personConverter;
}
There MAY be a nicer solution in CDI-style (JSR-299) but i've failed to make this one running:
<f:converter binding="#{cdiBean}" />
Where cidBean ought to be:
#Named class CdiBean implements Converter { #EJB ... }
Fails with 'Default behavior invoked of requiring a converter-id passed in the constructor'
Anyhow first approach using binding and app scoped JSF bean works.
The Seam Faces extension for JSF 2.0 and CDI allows #Inject support directly in Validators and Converters.
Check it out: http://ocpsoft.com/java/seam-faces-3-0-0-alpha2-jsf-2-0-just-got-even-easier/
i don't know if this solution is pretty... but it does work:
#ManagedBean
public class AcquisitionConverter implements Converter
{
#EJB
private AcquisitionService service;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
...
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
...
}
}
and
<h:inputText value="#{flowController.acquisition}" converter="#{acquisitionConverter}">
with jsf 2.1.3 (mojarra) and glassfish 3.1.1

Resources