users@glassfish.java.net

Re: Inconsistent behaviour between JSF2 and CDI injection in @FacesConverter . Possible Glassfish bug?

From: Dominik Dorn <dominik.dorn_at_gmail.com>
Date: Fri, 20 Aug 2010 13:42:55 +0200

I'm looking up the dao through the a BeanManager in the converter.
My solution is quite complex, but you should be able to extract the
things you need.

I have an AbstractConverter that looks like this:

public abstract class AbstractConverter<TYPE,KEY,DAO extends
GenericDao<TYPE,KEY>> implements Converter {

    protected Class entityClass;

    protected Class keyClass;

    protected Class daoClass;

    public BeanManager getBeanManager(FacesContext facesContext)
    {
        return (BeanManager) ((ServletContext)
facesContext.getExternalContext().getContext()).getAttribute("javax.enterprise.inject.spi.BeanManager");
    }

    protected DAO getDao(FacesContext context)
    {
        BeanManager bm = getBeanManager(context);
        Bean<DAO> bean = (Bean<DAO>) bm.getBeans(daoClass).iterator().next();
        CreationalContext<DAO> ctx = bm.createCreationalContext(bean);
        DAO dao = (DAO) bm.getReference(bean, daoClass, ctx);
        return dao;
    }

    protected AbstractConverter() {
        ParameterizedType genericSuperclass = (ParameterizedType)
getClass().getGenericSuperclass();
        this.entityClass = (Class<TYPE>)
genericSuperclass.getActualTypeArguments()[0];
        this.keyClass = (Class<KEY>)
genericSuperclass.getActualTypeArguments()[1];
        this.daoClass = (Class<DAO>)
genericSuperclass.getActualTypeArguments()[2];
    }

    public Object getAsObject(FacesContext facesContext, UIComponent
component, String value) {
        if (value == null || value.length() == 0) {
            return null;
        }
        return getDao(facesContext).find(getKey(value));
    }

    public abstract KEY getKey(String value);

    public abstract String getKeyOfEntity(TYPE t);
// {
// Long key;
// key = Long.valueOf(value);
// return (KEY) key;
// }

    String getStringKey(long value) {
        StringBuffer sb = new StringBuffer();
        sb.append(value);
        return sb.toString();
    }


    public String getAsString(FacesContext facesContext, UIComponent
component, Object object) {
        if (object == null) {
            return null;
        }
        if(object.getClass().equals(entityClass)){
            TYPE o = (TYPE) object;
            return getKeyOfEntity(o);
        } else {
            throw new IllegalArgumentException("object " + object + "
is of type " + object.getClass().getName() + "; expected type: " +
entityClass.getName());
        }
    }

}


The Converter then just looks like this:

@FacesConverter(forClass= Course.class)
public class CourseConverter extends AbstractConverter<Course, Long,
CourseDao> {
    @Override
    public Long getKey(String value) {
        return Long.valueOf(value);
    }

    @Override
    public String getKeyOfEntity(Course t) {
        return String.valueOf(t.getId());
    }
}


CourseDao extends GenericDao
public interface GenericDao<TYPE,KEY> {
    public TYPE create(TYPE object);

    public TYPE edit(TYPE object) ;

    public void remove(TYPE object);

    public TYPE find(KEY id);

    public List<TYPE> findAll() ;

    public List<TYPE> findRange(int[] range);

    public int count();

}



On Fri, Aug 20, 2010 at 1:34 PM, Craig Ringer
<craig_at_postnewspapers.com.au> wrote:
> On 20/08/10 18:42, Dominik Dorn wrote:
>
>> I came up with this a few months ago. The answer I got was that it's
>> not a bug in the implementation but in the specification that does not
>> specify how far CDI and JSF should work together.
>
> Hooray for complicated interlocking specs developed in parallel :S  . I
> thought CDI was suppoed to make things easier and more consistent, but
> so far I've just had problems with it compared to JSF2's injection features.
>
> Did you find a way to solve or work around this issue? Give up on
> Glassfish's CDI/Weld support as not production-ready and go back to pure
> JSF2? Lookup the EJB via JNDI instead? Avoid the need to use EJBs?
> Something else?
>
> I'm going to expose my ignorance of JNDI at this point and ask, if you
> used JNDI, how you looked up the EJB you needed. I've been trying, but
> just can't seem to obtain the bean.
>
> If I enumerate the entries under "java:module/env/" with something like:
>
> try {
>  InitialContext ctx = new InitialContext();
>  NamingEnumeration<NameClassPair> items = ctx.list("java:module/env/");
>  while (items.hasMoreElements()) {
>      NameClassPair p = items.next();
>      System.err.println("JNDI item: " + p.getName() +
>                         ": " + p.getClassName());
>  }
> } catch (NamingException ex) {
>  throw new RuntimeException(ex);
> }
>
> .... I can find the @Named model beans, but not the EJBs. A lookup for
> the fully qualified classname of the EJB under java:module/env/ throws a
> naming exception reporting that the class name can't be found.
>
> How does one obtain an EJB from a FacesConverter?
>
> ( and should I just switch to targeting JBoss AS + Seam, where this
> stuff reportedly works? )
>
> --
> Craig Ringer
>



-- 
Dominik Dorn
http://dominikdorn.com
http://twitter.com/domdorn
Tausche Deine Lernunterlagen auf http://www.studyguru.eu !