Scott
Scott

Reputation: 186

jsf converter loses injected property

I had this working before, but then I changed some things, and I can't get it to work again. I am trying to use my service tier to hit the database and get a correct object from my converter class, depending on what the user clicks. I inject the service property into my converter with spring. During debugging, I can see that the property gets sets properly. But then when I go to call getService, it is null.

@FacesConverter("PlaceConverter")

@SessionScoped public class PlaceConverter implements Converter {

private SearchQueryService searchQueryService;

/**
 * @return the searchQueryService
 */
public SearchQueryService getSearchQueryService() {
    return searchQueryService;
}

/**
 * @param searchQueryService the searchQueryService to set
 */
public void setSearchQueryService(SearchQueryService searchQueryService) {
    this.searchQueryService = searchQueryService;
}

@Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String submittedValue) {
        try {
            Criteria criteria = new Criteria();
            criteria.setId(Integer.parseInt(submittedValue));
            return getSearchQueryService().findPlaces(criteria).get(0);
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    return null;
}

@Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {
    ((Place) value).setCategory(" (" + ((Place) value).getCategory() + ")");
    return String.valueOf(((Place) value).getPlaceId());
}

}

<bean id="placeConverterBean" class="com.ghghg.converter.PlaceConverter">
    <property name="searchQueryService" ref="searchQueryServiceBean" />
</bean>

Upvotes: 1

Views: 1251

Answers (4)

Michał Kupisiński
Michał Kupisiński

Reputation: 3863

Converter comes to play before updating your model bean. When user fill some input and this value is transferred to server first are updated your server side components and next conversion has happened. Converted values as saved in your bean (with method getAsObject) and before rendering the view values from beans are again converted to String because from user side everything is a string (then method getAsString is invoked).

In summary - Converter methods are the best place to change user input into your application logic, bean fields and in other way to convert your logic, bean fields into user friendly strings.

Due to your question and problem. You mean that SearchQueryService isn't available inside getAsObject method. Try to add an addnotation @Resource with proper name attribute and then it should be injected by your container.

Upvotes: 0

Bob Brinks
Bob Brinks

Reputation: 1392

I got it to work like this in java EE with jsf 2.0. By making the converter a member of the backing bean. I instantiate this member using CDI but it should work the same with spring.

First the backing bean:

@ViewScoped
@ManagedBean
public class SomeView implements Serializable {

    private static final long serialVersionUID = 1L;

    @Inject
    private SomeConverter converter;

    public Converter getConverter() {
        return converter;
    }
}

And then this is the jsf xhtml:

<p:selectOneMenu id="someId" value="#{someView.value}" converter="#{someView.converter}">
    <f:selectItems value="#{someView.values}" var="object" itemLabel="#{object.name}" />
</p:selectOneMenu>

Upvotes: 0

BalusC
BalusC

Reputation: 1109262

Dependency injection in a converter works only if the converter is declared as a managed bean by the dependency injection framework in question. E.g. JSF's own @ManagedBean, or CDI's @Named, or Spring's @Component. You should remove the @FacesConverter altogether and reference the converter instance in EL scope instead of referencing it by the converter ID.

Thus, so

<h:inputXxx converter="#{placeConverter}" />

or

<f:converter binding="#{placeConverter}" />

instead of

<h:inputXxx converter="PlaceConverter" />

or

<f:converter converterId="PlaceConverter" />

Your concrete problem suggests that you were referencing it by converter ID (thus, via @FacesConverter). This way you end up getting a converter instance without any injected dependencies.

See also:

As to the role of the converter itself, this is mandatory because HTML code is represented as one large string and HTTP request parameter values can only be represented as strings. Complex Java objects would otherwise be printed via Object#toString() like so com.example.Place@hashcode, making it unusable in the server side.

Upvotes: 1

Scott
Scott

Reputation: 186

I found a better way, and probably more proper way to do get what I wanted. I was not completely sure how the converter works and how the value of the selected item gets passed back to the managed bean. I just declared a new Place object in my method, set the required values. Then I saw that it got passed to my managed bean

Upvotes: 0

Related Questions