32

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?

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
AlanObject
  • 8,408
  • 18
  • 72
  • 122

4 Answers4

65

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.

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • 3
    Well I'll be dambed. I implemented a workaround that basically calls the application to evaluate an expression from inside the converter, but I think this is more elegant. So I have another question @BalusC -- isn't about time you wrote a book on JSF? – AlanObject Sep 23 '11 at 16:53
  • Well it isn't like you would have to write much -- just edit all the stuff you have written already. Seriously I have thought of an outline for a book if you are interested in a collaboration just let me know. – AlanObject Sep 23 '11 at 19:45
  • 3
    Well can you believe it almost exactly one year after the original posting I run into this problem again on a new project, do a google search, and come with my own post! I don't remember writing the above but computers never lie. – AlanObject Sep 30 '12 at 00:44
  • @BalusC Like many other of your answers, people link to this one to this day, for example http://stackoverflow.com/questions/18183176/jsf-converter-for-selectonemenu. You might consider editing to include the support provided by Omnifaces in 1.6 once it's out :) – rdcrng Aug 13 '13 at 21:23
  • The [SelectItemsConverter](http://showcase.omnifaces.org/converters/SelectItemsConverter) from [OmniFaces] (http://code.google.com/p/omnifaces/) project save my day. Thanks @BalusC! – Gilberto Mar 18 '14 at 19:17
  • @BalusC You don't have to write a book. You should marry me. – Jin Kwon Nov 09 '16 at 08:02
6

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.

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
FuryFart
  • 2,083
  • 3
  • 22
  • 39
3

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.

CSchulz
  • 10,102
  • 9
  • 54
  • 107
Dar Whi
  • 822
  • 5
  • 14
2

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.

Community
  • 1
  • 1
Howard
  • 762
  • 8
  • 41