CDI Injection into a FacesConverter - jsf-2

From just a few searches, this seems like a problem that has been around for a while. I have written a FacesConverter that looks like the following. The object Category is a JPA entity and CategoryControl is the DAO that fetches it.
#FacesConverter(value = "categoryConverter")
public class CategoryConverter implements Converter {
#Inject private CategoryControl cc;
public CategoryConverter() { }
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (cc != null) return cc.getByName(value);
System.out.println("CategoryConverter().getAsObject(): no injection!");
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Category)) return null;
return ((Category) value).getName();
}
}
As you probably guessed by now, I never get the injection. I got this workaround from this page, which looks like this.:
Workaround for this problem: create this method in your localeController:
public Converter getConverter()
{
return FacesContext.getCurrentInstance().getApplication().createConverter("localeConverter");
}
and use converter="#{localeController.converter}" in your h:selectOneMenu.
However I can't make this work either. My backing bean creates and returns a converter all right, but it doesn't get the object injected into it.
I am using MyFaces CODI 1.0.1. With the current GlassFish/Weld container. Can anyone suggest a solution before I re-code to not use a Converter?

Replace
#FacesConverter(value = "categoryConverter")
by
#Named
and use
<h:inputSomething converter="#{categoryConverter}" />
or
<f:converter binding="#{categoryConverter}" />
instead of
<h:inputSomething converter="categoryConverter" />
or
<f:converter converterId="categoryConverter" />
By the way, similar problem exist for #EJB inside a #FacesConverter. It however offers a way to be grabbed by JNDI manually. See also Communication in JSF 2.0 - Getting an EJB in #FacesConverter and #FacesValidator. This way you can use a #FacesConverter(forClass=Category.class) without manually defining it everytime. Unfortunately I can't tell from top of head how to realize that for CDI beans.
Update: if you happen to use JSF utility library OmniFaces, since version 1.6 is adds transparent support for using #Inject and #EJB in a #FacesConverter class without any additional configuration or annotations. See also the CDI #FacesConverter showcase example.

The #Inject Annotation only works in CDI managed instances. If you want to use CDI features inside a non-CDI managed instance (Like a JSF Validator or a JSF Converter) you can just programm against the CDI API.
This works only in at least Java EE 7 + CDI 1.1 server.
#FacesValidator("userNameValidator")
public class UserNameValidator implements Validator {
private UserService userService;
public UserNameValidator(){
this.userService = CDI.current().select(UserService.class).get();
}
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
....
}
}
https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/CDI.html
With all the AnnotationHell in Java EE people forget how to code.

Just use #Advanced of CODI for your #FacesConverter see the Wiki.
As soon as a converter or a validator is annotated with #Advanced it's possible to use #Inject.

Per BalusC's answer here, I decided to add JSF (requestscoped) managed beans that only contained #FacesConverter and Converter to resolve this issue in my app, since I'm migrating from JSF managed beans to CDI managed beans.
I tried CODI #Advanced against #FacesConverter, but it does not inject the bean at all.

Related

EJB as an Interface is not injected

I defined an interface.
#Local
public interface MessageService {
}
And an implementation.
#Stateless
public class MessageServiceSome implements MessageService {
}
When I tried to inject it into my resource class, I got null.
//#Path("/messages") // I'M NOT GOING TO MAKE THIS STATELESS!!!
public class MessagesResource {
// none of follwoing options works
// leaves the field null
#Inject
//#EJB
//#EJB(beanName = "MessageServiceSome")
private MessageService messageService;
}
How can I solve this?
UPDATE
I think I have to admit that my question is not good enough.
The MessagesResource class was actually a sub resource. I didn't know the difference.
There are two very good threads for this issue.
https://stackoverflow.com/a/36291890/330457
https://stackoverflow.com/a/24670218/330457
One is using ResourceContext and the other is using Inject.
Both threads are saying they work but I only succeeded with #Inject.
With little information provided, you have probably two quick options you can try:
leave #Inject only, if your project/container is CDI enabled
#Inject
private MessageService messageService;
leave #EJB only, do you really need the beanName ?
#EJB
private MessageService messageService;
on of the two should solve the issue.
[UPDATE]
Otherwise have a look at the app server start up log, and see if the bean has been deployed.

#Named bean not accessible in jsf

my environment is: Maven 3, JSF 2, Tomcat 7, Java 6. I am trying to use the java #Named annotations for my beans, that I use in JSF. The project is simple, with one TestBean that has one getter and setter for one property called text.
#Named
public class TestBean {
String text = "Hello World"
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
}
In my jsf file when I try:
#{testBean.text}
I get no error but also nothing is shown. What do I have to do to be able to access the bean?
#Named annotation only exposes your bean in EL context, it doesn't give it a scope. This defaults to 'dependent' pseudo-scope. Dependent beans are not managed, they are just inserted at injection points and that's it.
Try explicitly adding scope. Also you can use built-in #Model stereotype, which is simply a combination of #Named and #RequestScoped.

CDI/WELD can a custom qualifier work in combination with the #Named annotation?

While having a custom qualifier for CDI support as followed:
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface QualifiedFooBean {
}
#QualifiedFooBean
public class FooBean implements ImplFooBean {
}
public interface ImplFooBean {
}
I would like to bind FooBean #{fooBean} directly without requiring a wrapper or processor (seen from this example). The annotation "Named" (in class FooBean) seems not to work for my class layout.
My solution (without wrapper) which I'm wondering why it's not working and invoking: Target Unreachable, identifier 'fooBean' resolved to null
#Named
#QualifiedFooBean
public class FooBean implements ImplFooBean {
}
Has anyone any idea?
A wrapper is not needed. My solution is perfectly valid. It's also allowed to add Named in combination of a custom qualifier (in my case QualifiedFooBean). I had to just create an empty beans.xml file in WEB-INF folder in order to get CDI to work. Anyhow The question itself explains how custom qualifiers can work. You can also prefill beans.xml with following content:
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
It will serve as a skeleton for future use, if you need to configure more fancy stuff with CDI.
Adding #Named to your bean should work : it works for me.
In Fact #Named is a qualifier, when JSF resolve the Bean for displaying it does a lokup based on #Named qualifier. In CDI a bean is found if the lookup side (i.e. Injection point) ask for a subset of its Qualifier.
For instance a bean qualified like that :
#QualifiedFooBean
#SecondQualifier
public class FooBean {}
Will be found (if there is no ambiguous resolution) by
#Inject
#SecondQualifier
FooBean bean;
or even :
#Inject
FooBean bean;
But not by
#Inject
#SecondQualifier
#ThirdQualifier
FooBean bean;
So you can add the #Named qualifier and let CDI resolution engine do its job.

Injecting Resources Into UIComponent (aka does CDI work here?)

I am writing a (composite) component that needs to interact with my DAO. Here is how the Java part is declared:
#FacesComponent(value="selectLocation")
public class SelectLocation extends UINamingContainer {
To get the DAO object, I tried the CDI annotation:
#Inject private LocationControl lc;
And that didn't work so I tried the Faces annotation:
#ManagedProperty (value = "#{locationControl}") private LocationControl lc;
Both cases nothing happens -- the property lc ends up as null after the constructor finishes.
I use CDI in all my backing beans and it all works. This would be using Weld inside GlassFish 3.1.1. Any suggestions on how to get the resource?
I have a work-around for now, which is to basically put in the boiler-plate code that CDI et. al. is supposed to do away with. I now have this method:
public LocationControl getLocationControl() {
if (lc != null) return lc;
FacesContext fc = getFacesContext();
Object obj = fc.getApplication().evaluateExpressionGet(fc, "#{locationControl}", LocationControl.class);
if (obj instanceof LocationControl) lc = (LocationControl) obj;
return lc;
}
I would like to know if anyone has a better solution.
I don't know if it also works for components, but with CDI + MyFaces CODI you have #Advanced to mark e.g. Phase-Listeners which should be able to use #Inject. If it doesn't work, you could create a feature request in their JIRA. They are pretty fast and there are frequent releases.
Or you use:
MyBean myBean = BeanManagerProvider.getInstance().getContextualReference(MyBean.class);
manually.
There is a way to do this work without workarounds?
Yes, just use a backing bean the usual way.
<x:someComponent value="#{someBean.someProperty}" />
Wrap if necessary in a reusable tagfile/composite to keep it DRY:
<my:someComponent />

Apache MyFaces CODI PageBean: "Argument bean must not be null"

I'm currently experimenting a little with Apache MyFaces CODI. I managed to create a simple working Typesafe-Navigation using #Page and an action Method which returns a Class.
However, when I'm adding an #PageBean-Annotation with e.g. MyPageBean.class, the following exception is thrown when I try to navigate to the page:
exception
javax.servlet.ServletException: WELD-001324 Argument bean must not be null
root cause
org.jboss.weld.exceptions.IllegalArgumentException: WELD-001324 Argument bean must not be null
The code of my page is:
#Page
#PageBean(MyPageBean.class)
public final class MyPage implements ViewConfig, Serializable {
}
and my Page-Bean:
public class MyPageBean implements Serializable {
#InitView
protected void initView() { }
#PrePageAction
protected void prePageAction() { }
#PreRenderView
protected void preRenderView() { }
}
And the Action-Method called by the Facelets Page:
public Class<? extends ViewConfig> nextPage() {
return MyPage.class;
}
Does the pageBean-Class (MyPageBean) need to have a specific annotation or interface? I already tried using #Model but this didn't change anything.
My Configuration:
Jave EE6 with Weld (created using the weld-archetype)
Glassfish 3.1 Community Edition (The one shipped with Netbeans 7)
JSF2.0 (Mojarra 2.1)
EJB 3.1
MyFaces CODI 0.9.4
RichFaces 4.0.0.Final
Thanks for any advices!
Best regards,
Robert
If you don't use any specific scope, it will end up being #Dependent.
I suggest to at least use #RequestScoped (take care, don't use the javax.faces.bean.RequestScoped, but the annontation from CDI!)
Oki, talked with Gerhard now as he has more experience with CODI on Weld.
Apparently this seems to be an error in the Weld version you use. This should be working in weld-1.1.1.Final https://github.com/weld/core/tree/1.1.1.Final
Please try to replace the weld-osgi-bundle in your glassfish with the one from weld 1.1.1.Final
cp target/weld-osgi-bundle-1.1.1.jar /opt/sun/glassfish/glassfish/modules/weld-osgi-bundle.jar
if it works: credits go to os890 ;)

Resources