0

I am working on a web application using PrimeFaces, JPA, Hibernate and JSF 2.0.

I have a converter for my JSF p:selectOneMenu. My problem is, when I run my application the Service descriptifService is not autowired, it return NULL !

The converter :

@Component
@FacesConverter(value = "descriptifConverter")
public class DescriptifConverter implements Converter {

@Autowired
@RmiClient
private IDescriptifService descriptifService;

@Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
    if (arg2 == null || arg2.isEmpty()) {
        return null;
    }

    String descriptif = arg2;
    Long value = Long.valueOf(descriptif);
    DescriptifDto result = new DescriptifDto();
    result = descriptifService.findById(value);
    return result;
}

@Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {

    if(arg2 == null || ((DescriptifDto) arg2).getIdDescriptif() == null) return null;

    DescriptifDto descriptif = new DescriptifDto();

    if(arg2 instanceof DescriptifDto) {
        descriptif = (DescriptifDto) arg2;
        String idDescriptif = descriptif.getIdDescriptif().toString();
        return (idDescriptif != null) ? String.valueOf(idDescriptif) : null;
    } else throw new ConverterException("Something wrong!" + arg2.hashCode() + arg2.toString());

}
}

The JSF code :

                        <p:selectOneMenu value="#{lotController.selectedDescriptif}"
                            effect="fade">
                            <f:selectItems value="#{lotController.listDescriptifs}" var="descriptif"
                                itemLabel="#{descriptif.libelle}" itemValue="#{descriptif}" />
                                <f:converter binding="#{descriptifConverter}" />
                        </p:selectOneMenu>

2 Answers2

2

Here you have two options:

1 - Register a context provider bean:

AppContext Class:

import org.springframework.context.ApplicationContext;

public class AppContext {

    private static ApplicationContext ctx;

    public static void setApplicationContext(
            ApplicationContext applicationContext) {
        ctx = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return ctx;
    }

}

ApplicationContextProvider class:

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class ApplicationContextProvider implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        AppContext.setApplicationContext(applicationContext);
    }

}

Register the bean:

<bean id="contextApplicationContextProvider" class="com.example.ApplicationContextProvider" />

Now, through the context, you can get a reference to your service bean anyware:

IDescriptifService descriptifService = AppContext.getApplicationContext().getBean( IDescriptifService.class);

2 - Store the converted values inside the ViewMap (inspired in this post)

I like this solution because it doesn't required database access which improves the performance of the application.

AbstractConverter class

import java.util.HashMap;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;

public abstract class AbstractConverter implements Converter {

    private static final String KEY = "com.example.converters.AbstractConverter";

    protected Map<String, Object> getViewMap(FacesContext context) {
        Map<String, Object> viewMap = context.getViewRoot().getViewMap();
        @SuppressWarnings({ "unchecked", "rawtypes" })
        Map<String, Object> idMap = (Map) viewMap.get(KEY);
        if (idMap == null) {
            idMap = new HashMap<String, Object>();
            viewMap.put(KEY, idMap);
        }
        return idMap;
    }

    @Override
    public final Object getAsObject(FacesContext context, UIComponent c,
            String value) {
        if (value == null || value.isEmpty()) {
            return null;
        }
        return getViewMap(context).get(value);
    }

    @Override
    public final String getAsString(FacesContext context, UIComponent c,
            Object value) {
        if (value != null) {
            String id = getConversionId(value);
            if (id == null || id.isEmpty()) {
                throw new IllegalArgumentException(
                        "Objeto não pode ser convertido.");
            }
            getViewMap(context).put(id, value);
            return id;
        }
        return null;
    }
    //Every concrete class must provide an unique conversionId String
    //to every instance of the converted object
    public abstract String getConversionId(Object value);
}

Here we create a storage place inside the ViewMap. We can now use it to store any converter object we need.

Here is an example of a concrete converter:

EntityConverter class

import javax.faces.convert.FacesConverter;

import com.example.AbstractEntity;

@FacesConverter("entity")
public class EntityConverter extends AbstractConverter {

    @Override
    public String getConversionId(Object value) {

        if (value instanceof AbstractEntity) {
            AbstractEntity entity = (AbstractEntity) value;
            StringBuilder sb = new StringBuilder();
            sb.append(entity.getClass().getSimpleName());
            sb.append("@");
            sb.append(entity.getId());
            return sb.toString();
        }

        return null;
    }
}
Community
  • 1
  • 1
0

A late response, but I had the same problem of not being able to Autowire Spring beans into a JSF Converter, so I removed the @FacesConverter annotation and declared the converter component as session scoped, then, as you did, using the f:converter tag with binding attribute solved the problem. In your case:

@Component
@Scope(WebApplicationContext.SCOPE_SESSION)
public class DescriptifConverter implements Converter {
...
}

should work...

Lotzy
  • 439
  • 1
  • 4
  • 12