Search code examples
javajsfejbconvertersselectmanylistbox

JSF selectManyListBox with converter not working


Straight to the point, I get ClassCastException: java.lang.String cannot be cast com.jsf.domain.Owner I assume there is a problem with a converter but I have no idea where it is.

Html :

<h:selectManyListbox value="#{myBean.target}" converter="#{myConverter}">
    <f:selectItems value="#{myBean.source}" var="c" itemValue="#{c}"    itemLabel="#{c.name} #{c.surname}"/>
</h:selectManyListbox>
<h:commandButton value="Ok" action="#{myBean.add()}"/>

Bean left just the most important bits:

@SessionScoped
@Named("myBean")
public class MyFormBean implements Serializable {

    //Car has manytomany relationship with the owner
    private Car car = new Car();    
    private List<Owner> target; 

    @Inject
    OwnerManager om;    
    @Inject
    CarManager mm;

    public String add(){
        mm.addOwners(car.getId(), target);  
        retur null;
    }

    public List<Owner> getSource(){
        om.getAllOwners();
    }   

    public List<Owner> getTarget(){
        return target;  
    }

    public void setTarget(List<Owner> target){
        this.target = target;
    }
}

And this is my converter :

@FacesConverter("myConverter")
public class myConverter implements Converter {

    @Inject
    CarManger mm;

    @Override Object getAsObject(FacesContext context, UIComponent component, String value){
        if(value == null){
            return null;
        }
        return mm.getEntityManager.find(Owner.class, LongValueOf(value));
    }

    @Override String getAsString(FacesContext context, UIComponent component, Object value){
        if(value == null){
            return null;
        }
        if(value instanceof Car){
            return String.valueOf(((Owner) value).getId());
        }
        return null;
    }
}

Also another question, hopefully I won't be told to make a separate post for it. Am I understanding it correctly that when the source is a complex object first the getAsString method is called when retrieving it and when returning it to the source the getAsObject is called? I appreciate all the help.

Edit :

    [2014-01-01T22:03:34.266+0100] [glassfish 4.0] [WARNING] [] [javax.enterprise.web] [tid: _ThreadID=18 _ThreadName=http-listener-1(1)] [timeMillis: 1388610214266] [levelValue: 900] [[
      StandardWrapperValve[FacesServlet]: Servlet.service() for servlet FacesServlet threw exception
    java.lang.ClassCastException: java.lang.String cannot be cast to com.jsf.domain.Owner
        at com.jsf.domain.CarManager.addOwnerToCar(CarManager.java:33)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1081)
        at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1153)
        at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4695)
        at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:630)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
        at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:582)
        at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:46)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
        at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:582)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:140)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
        at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:369)
        at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:4667)
        at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4655)
        at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
        at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
        at com.sun.proxy.$Proxy386.addOwnerToCar(Unknown Source)
        at com.jsf.service.__EJB31_Generated__CarManager__Intf____Bean__.addOwnerToCar(Unknown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:396)
        at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:108)
        at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56)
        at org.jboss.weld.bean.proxy.InjectionPointPropagatingEnterpriseTargetBeanInstance.invoke(InjectionPointPropagatingEnterpriseTargetBeanInstance.java:63)
        at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:101)
        at com.jsf.service.CarManager$Proxy$_$$_Weld$EnterpriseProxy$.addOwnerToCar(Unknown Source)
        at com.jsf.web.MyBean.addCar(MyBean.java:61)
        at com.jsf.web.MyBean$Proxy$_$$_WeldClientProxy.addCar(Unknown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at javax.el.ELUtil.invokeMethod(ELUtil.java:326)
        at javax.el.BeanELResolver.invoke(BeanELResolver.java:536)
        at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:256)
        at com.sun.el.parser.AstValue.invoke(AstValue.java:269)
        at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
        at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
        at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
        at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
        at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
        at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
        at javax.faces.component.UICommand.broadcast(UICommand.java:315)
        at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
        at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
        at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
        at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
        at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
        at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
        at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
        at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
        at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
        at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
        at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
        at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
        at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
        at java.lang.Thread.run(Thread.java:724)
    ]]

addOwners method

  @PersistenceContext
  EntityManager em;

  public void addOwners(Long carId, List<Owner> owners){
      Car car = em.find(Car.class, carId);
      for(Owner o : owners){
          car.getOwners().add(o);
      }
  }

Solution

  • The first problem is that a Converter must not return null from its getAsString method. From the javadoc:

    Returns: a zero-length String if value is null, otherwise the result of the conversion

    If you violate that contract and return null, expect things to break. (Seriously, I've seen it cause some pretty strange behavior in Mojarra.)

    The second problem is that converter="#{myConverter}" is an expression that expects a scoped variable named myConverter, but there is no such variable. The @FacesConverter("myConverter") annotation does not place a variable into any scope, so it does not in any way make #{myConverter} a valid expression. Instead, using the annotation registers a converter class in the JSF application under the converter ID given as the value argument of the annotation, using the addConverter(String, String) method of javax.faces.application.Application.

    Remove the converter= attribute, and add a child element inside the <h:selectManyListBox> like this:

    <f:converter converterId="myConverter"/>