9 Replies Latest reply on Feb 28, 2008 1:04 PM by Marine Wacheux

    another listShuttle help

    1 1 Newbie

      hi...
      I'm having some troubles to submit a form with a listShuttle inside.
      this is my converter:

      public class BeanCooGradeConverter implements Converter {
      
       public Object getAsObject(FacesContext context, UIComponent component,
       String value) {
       try {
       int index = value.indexOf(':');
      
       return new SelectItem(value.substring(0, index), value
       .substring(index + 1));
       } catch (Exception e) {
       e.printStackTrace();
      
       return null;
       }
       }
      
       public String getAsString(FacesContext context, UIComponent component,
       Object value) {
       try {
       SelectItem selectItem = (SelectItem) value;
      
       return selectItem.getValue() + ":" + selectItem.getLabel();
       } catch (Exception e) {
       e.printStackTrace();
      
       return null;
       }
       }
      
      }
      


      this is my jsf-config.xml:
      ...
      <managed-bean>
       <managed-bean-name>BeanCooGrade</managed-bean-name>
       <managed-bean-class>jsf.bean.BeanCooGrade</managed-bean-class>
       <managed-bean-scope>session</managed-bean-scope>
      </managed-bean>
      <managed-bean>
       <managed-bean-name>BeanCooGradeConverter</managed-bean-name>
       <managed-bean-class>jsf.converter.BeanCooGradeConverter</managed-bean-class>
       <managed-bean-scope>application</managed-bean-scope>
      </managed-bean>
      ...
      


      this is my jsp:
      <rich:listShuttle sourceValue="#{BeanCooGrade.disciplinasFonte}"
       targetValue="#{BeanCooGrade.disciplinasDestino}" var="item"
       sourceCaptionLabel="Disciplinas disponÃÂÂÂveis"
       targetCaptionLabel="Disciplinas da grade"
       copyAllControlLabel="Adicionar todas" copyControlLabel="Adicionar"
       removeAllControlLabel="Remover todas" removeControlLabel="Remover"
       orderControlsVisible="false" fastOrderControlsVisible="false"
       converter="#{BeanCooGradeConverter}">
       <rich:column>
       <h:outputText value="#{item.label}"></h:outputText>
       </rich:column>
      </rich:listShuttle>
      


      as you can see, my "item" in the listShuttle ia a SelectItem bean...

      this is the warning generated by the commandButton click...
      INFO: WARNING: FacesMessage(s) have been enqueued, but may not have been displayed.
      sourceId=j_id_jsp_1122326479_1:j_id_jsp_1122326479_14[severity=(ERROR 2), summary=(j_id_jsp_1122326479_1:j_id_jsp_1122326479_14: Validation Error: Value javax.faces.model.SelectItem@a6a21a is not valid), detail=(j_id_jsp_1122326479_1:j_id_jsp_1122326479_14: Validation Error: Value javax.faces.model.SelectItem@a6a21a is not valid)]
      

      obs: the action in the managed bean in never called... :/

      thanks.

        • 1. Re: another listShuttle help
          Ilya Shaikovsky Master

          did you implemented eauals() and hashCode() in your item class?

          I advice you to llok through demo source code once again.

          • 2. listShuttle : validation problem
            Marine Wacheux Newbie

            Hello,

            I meet also the same validation problem when I submit a form with a listShuttle :

            body:formChoixDest:shuttleChoixDest: Validation Error: Value xxxxx.DataModelCorrespondant@f9c05581 is not valid


            The listShuttle manage objects of type "DataModelCorrespondant", that override "equals" and "hashCode" methods.
            I also use a specific converter.
            Is there something I'm missing ?

            Thanks for any help...


            Type managed by listShuttle :

            public class DataModelCorrespondant implements Serializable {
            
             private static final long serialVersionUID = -6648673826653523852L;
            
             private Long id;
             private String nomPrenom;
             private Boolean isMedecinTraitantDuPatient;
             private Boolean isAutreCorrespondantDuPatient;
            
             public DataModelCorrespondant() {}
            
             public DataModelCorrespondant(CorrespondantMedical corr,
             Boolean isMedecinTraitant, Boolean isAutreCorresp) {
             this.id = corr.getId();
             this.nomPrenom = corr.getNom() + " " + corr.getPrenom();
             this.isMedecinTraitantDuPatient = isMedecinTraitant;
             this.isAutreCorrespondantDuPatient = isAutreCorresp;
             }
            
             public Long getId() {
             return id;
             }
             public void setId(Long id) {
             this.id = id;
             }
             public String getNomPrenom() {
             return nomPrenom;
             }
             public void setNomPrenom(String nomPrenom) {
             this.nomPrenom = nomPrenom;
             }
             public Boolean getIsMedecinTraitantDuPatient() {
             return isMedecinTraitantDuPatient;
             }
             public void setIsMedecinTraitantDuPatient(Boolean isMedecinTraitantDuPatient) {
             this.isMedecinTraitantDuPatient = isMedecinTraitantDuPatient;
             }
             public Boolean getIsAutreCorrespondantDuPatient() {
             return isAutreCorrespondantDuPatient;
             }
             public void setIsAutreCorrespondantDuPatient(
             Boolean isAutreCorrespondantDuPatient) {
             this.isAutreCorrespondantDuPatient = isAutreCorrespondantDuPatient;
             }
            
             @Override
             public boolean equals(Object other) {
             if (this == other) {
             return true;
             }
             if (other == null) {
             return false;
             }
             if (getClass() != other.getClass()) {
             return false;
             }
            
             final DataModelCorrespondant corr = (DataModelCorrespondant) other;
            
             if ( id != 0 && corr.getId() != 0 ) {
             return (id == corr.getId() );
             }
             if ( ( nomPrenom == null && corr.getNomPrenom() != null) ||
             ( nomPrenom != null && !nomPrenom.equals(corr.getNomPrenom()) )
             ) return false;
             if ( isMedecinTraitantDuPatient != corr.getIsMedecinTraitantDuPatient() ) return false;
             if ( isAutreCorrespondantDuPatient!= corr.getIsAutreCorrespondantDuPatient() ) return false;
            
             return true;
             }
            
             @Override
             public int hashCode() {
             int result = 0;
             if (nomPrenom != null) result = 29 * result + nomPrenom.hashCode();
             if (isMedecinTraitantDuPatient != null) { if (isMedecinTraitantDuPatient) result++; }
             if (isAutreCorrespondantDuPatient != null) { if (isAutreCorrespondantDuPatient) result++; }
             return result;
             }
            
            }



            Converter :

            public class DataModelCorrespondantConverter implements Converter {
            
             private final static String SEP = ":";
            
             public Object getAsObject(FacesContext context, UIComponent component,
             String value) {
            
             int indexDeb = 0;
             int indexFin = value.indexOf(SEP);
             String idS = value.substring(indexDeb, indexFin);
             indexDeb = indexFin + 1;
             indexFin = value.indexOf(SEP, indexDeb);
             String isMedTrtS = value.substring(indexDeb, indexFin);
             indexDeb = indexFin + 1;
             indexFin = value.indexOf(SEP, indexDeb);
             String isAutreCorrS = value.substring(indexDeb, indexFin);
             indexDeb = indexFin + 1;
             String nomPrenom = value.substring(indexDeb);
            
             DataModelCorrespondant dmc = new DataModelCorrespondant();
             dmc.setId(Long.valueOf(idS));
             dmc.setIsMedecinTraitantDuPatient(Boolean.valueOf(isMedTrtS));
             dmc.setIsAutreCorrespondantDuPatient(Boolean.valueOf(isAutreCorrS));
             dmc.setNomPrenom(nomPrenom);
            
             return dmc;
             }
            
             public String getAsString(FacesContext context, UIComponent component,
             Object value) {
            
             DataModelCorrespondant dmc = (DataModelCorrespondant) value;
            
             String resultat = dmc.getId().toString()
             + SEP + dmc.getIsMedecinTraitantDuPatient().toString()
             + SEP + dmc.getIsAutreCorrespondantDuPatient().toString()
             + SEP + dmc.getNomPrenom();
            
             return resultat;
             }
            
            }



            In JSP :

            <rich:modalPanel id="modalpanelChoixDest" minHeight="400"
             minWidth="700">
            
             <a4j:outputPanel ajaxRendered="true" id="divBarreEtatModalPanel"
             layout="block" styleClass="DIV_MSG_MODAL_PANEL">
             <t:messages showSummary="false" showDetail="true" tooltip="true"
             errorClass="MSG_ERR" fatalClass="MSG_ERR" warnClass="MSG_WARN"
             infoClass="MSG_INFO" />
             </a4j:outputPanel>
            
             <h:form id="formChoixDest">
            
             <rich:listShuttle id="shuttleChoixDest" converter="DataModelCorrespondantConverter"
             sourceValue="#{redactionCourrierPatientForm.destinatairesPossibles}"
             targetValue="#{redactionCourrierPatientForm.destinatairesChoisis}"
             var="elt">
             <h:column>
             <t:outputText value="#{elt.nomPrenom}"/>
             <t:outputText value="#{elt.isMedecinTraitantDuPatient}"/>
             </h:column>
            
             </rich:listShuttle>
            
            
             <%-- BOUTONS DE VALIDATION/ANNULATION --%>
            
             <t:panelGroup layout="block" styleClass="DIV_BOUTONS_CENTRES">
             <%-- Les proprietes reRender et oncomplete sont mises a jour dans le bean --%>
             <a4j:commandButton id="btnValider" type="submit"
             binding="#{redactionCourrierPatientForm.uiBtnValiderChoixDest}"
             reRender="divBarreEtatModalPanel"
             actionListener="#{redactionCourrierPatientController.validerChoixDest}"
             styleClass="BTN_VALIDER" value=" " title="#{msgG.Valider}" />
             <a4j:commandButton id="btnAnnuler" reRender="divBarreEtat"
             onclick="cacherFenChoixDest();" styleClass="BTN_ANNULER"
             value=" " title="#{msgG.Annuler}" />
             </t:panelGroup>
            
             </h:form>
            
            </rich:modalPanel>


            • 3. Re: another listShuttle help
              Marine Wacheux Newbie

              Precisions :

              I did a test using a simple inputText with the converter and that worked without validation problem => The converter seems to be correct.

              <t:inputText id="test" value="#{redactionCourrierPatientForm.inTest}" converter="DataModelCorrespondantConverter"/>


              When validating the form with listShuttle, before displaying the validation error, debugger pass through getAsObject converter method twice if there are 2 elements in listShuttle, and seems to do work correctly. Then, validation error appear. Debugger don't pass through action method.

              Also, I verified values returned by hashCode method before converting object to String (before page display), and after converting String to object (after submit) => Values are the same for a given object.

              Thanks for help...


              • 4. Re: another listShuttle help
                Marine Wacheux Newbie

                Any idea, about this Validation error, please ?

                I didn't find any RF about this in JIRA issue tracker.
                Did someone else get this error ?

                Thanks

                • 5. Re: another listShuttle help
                  Ilya Shaikovsky Master

                  please check out demosite sample and explore our code for list shuttle usage.

                  • 6. Re: another listShuttle help
                    Marine Wacheux Newbie

                    Hi,

                    Thanks for your reply. That is what I did : look at demo source code, and look at developer guide, as I did for all other RichFaces components. But I still can't see where is my mistake.
                    I'm now thinking about making this "manually", without listShuttle, as I can't make it work... unless someone can point me on the mistake.

                    • 7. Re: another listShuttle help
                      Ilya Shaikovsky Master

                      you could send me the war file (with libs and sources) directly.. Will answer in this thread.

                      • 8. Re: another listShuttle help
                        Marine Wacheux Newbie

                        Thank you very much for your proposal, but it will be quite difficult, as it is part of a quite big project.

                        However, I downloaded RichFaces sources, in order to study the problem in debug mode.
                        Here is where the problem seems to be :

                        - I submit the form containing listShuttle component

                        - In UIListShuttle.processDecodes(...) method, it does the following test :

                        if (!isSuitableValue(modelSourceValue, value) && !isSuitableValue(modelTargetValue, value)) {
                         String messageText = Messages.getMessage(
                         Messages.INVALID_VALUE, MessageUtil.getLabel(faces, this), value);


                        - In UIOrderingBaseComponent.isSuitableValue(...) method, it does :
                         protected boolean isSuitableValue(Object value, Object restoredObject) {
                         if (value instanceof Object[]) {
                         Object[] objects = (Object[]) value;
                         for (int i = 0; i < objects.length; i++) {
                         Object object = objects;
                        
                         if (object != null && object.equals(restoredObject)) {
                         return true;
                         }
                         }
                        
                         return false;
                         } else {
                         if (value != null) {
                         /*************** THE PROBLEM IS HERE ******************************/
                         return ((Collection) value).contains(restoredObject);
                         /*************** THE PROBLEM IS HERE ******************************/
                         } else {
                         return false;
                         }
                         }


                        When it test if "value" contains "restoredObject", it should be true (the object is in list), but it returns false.

                        I thought it was because the DataModelCorrespondant.equals(...) method return a wrong result, but it never goes through this method....

                        Is it normal, that equals method isn't called ?
                        Any idea, please ?

                        • 9. Re: another listShuttle help
                          Marine Wacheux Newbie

                          Arghhh !! I found the mistake...
                          In fact, the equals method is called (I don't know why no "System.out.println" appeared in my previews tests, and why breakpoint wasn't reached).
                          And this equal method is wrong !

                          return (id == corr.getId() );

                          id are of "Long" type and not "long" => Correct test is :
                          return (id.equals(corr.getId()));



                          So much time lost for that... :(
                          But now, it works like a charm !