Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CDI Injection into a FacesConverter

Tags:

jsf-2

cdi

myfaces

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?

like image 921
AlanObject Avatar asked Sep 23 '11 15:09

AlanObject


2 Answers

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.

like image 60
BalusC Avatar answered Oct 09 '22 06:10

BalusC


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.

like image 40
FuryFart Avatar answered Oct 09 '22 07:10

FuryFart