How to inject @EJB, @PersistenceContext, @Inject, @Autowired, etc in @FacesConverter?
converters, dependency-injection, ejb, jsf
Solution
Can I use `@EJB` to inject my service into a `@FacesConverter`?
No, not until JSF 2.3 is released. The JSF/CDI guys are working on that for JSF 2.3. See also JSF spec issue 1349 and this related "What's new in JSF 2.3?" article of my fellow Arjan Tijms. Only then dependency injection like `@EJB`, `@PersistenceContext`, `@Inject`, etc will work in a `@FacesConverter` when you explicitly add `managed=true` attribute to the annotation.
@FacesConverter(value="yourConverter", managed=true)
public class YourConverter implements Converter {
@Inject
private YourService service;
// ...
}
If not, what's the "correct" way to do this?
Before JSF 2.3, you have several options:
Make it a managed bean instead. You can make it a JSF, CDI or Spring managed bean via `@ManagedBean`, `@Named` or `@Component`. The below example makes it a JSF managed bean.
@ManagedBean
@RequestScoped
public class YourConverter implements Converter {
@EJB
private YourService service;
// ...
}
And the below example makes it a CDI managed bean.
@Named
@RequestScoped
public class YourConverter implements Converter {
@Inject
private YourService service;
// ...
}
Reference it as `<h:inputXxx converter="#{yourConverter}">` instead of `<h:inputXxx converter="yourConverter">`, or as `<f:converter binding="#{yourConverter}">` instead of `<f:converter converterId="yourConverter">`. Don't forget to remove the `@FacesConverter` annotation!
The disadvantage is that you cannot specify `forClass` and thus need to manually define the converter everywhere in the view where necessary.
Inject it in a regular managed bean instead.
@ManagedBean
@RequestScoped
public class YourBean {
@EJB
private YourService service;
// ...
}
And in your converter, grab or call it via EL.
YourBean yourBean = context.getApplication().evaluateExpressionGet(context, "#{yourBean}", YourBean.class);
// Then e.g. either
YourEntity yourEntity = yourBean.getService().findByStringId(value);
// Or
YourEntity yourEntity = yourBean.findEntityByStringId(value);
This way you can keep using `@FacesConverter`.
Manually grab the EJB from JNDI.
YourService yourService = (YourService) new InitialContext().lookup("java:global/appName/YourService");
The disadvantage is that there is a certain risk that this is not entirely portable. See also Inject EJB bean from JSF managed bean programmatically.
Install OmniFaces. Since version 1.6, it transparently adds support for `@EJB` (and `@Inject`) in a `@FacesConverter` without any further modification. See also the showcase. If you happen to need the converter for `<f:selectItem(s)>`, then the alternative is to use its `SelectItemsConverter` which will automatically perform the conversion job based on select items without the need for any database interaction.
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
See also Conversion Error setting value for 'null Converter'.
See also:
- How to inject in @FacesValidator with @EJB, @PersistenceContext, @Inject, @Autowired
- CDI Injection into a FacesConverter
- Getting an `@EJB` in a `@FacesValidator` and `@FacesConverter`
Problem
How can I inject a dependency like `@EJB`, `@PersistenceContext`, `@Inject`, `@AutoWired`, etc in a `@FacesConverter`? In my specific case I need to inject an EJB via `@EJB`: ``` @FacesConverter public class MyConverter implements Converter { @EJB protected MyService myService; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { // myService.doSomething } } ``` However, it didn't get injected and it remains `null`, resulting in NPEs. It seems that `@PersistenceContext` and `@Inject` also doesn't work. How do I inject a service dependency in my converter so that I can access the DB?