0

In my JSF application using RichFaces, I have a screen with rich:dataTable that displays my objects, and a column that refers to another page, with the details of the selected record so that it can be used.

In this second page, after completing the requested data, when running submit, the validation returns the message:

:Value is not a valid option.

Look that, unlike the problem cited in this post, the name of the problem field is not being displayed.

During debugging, I noticed that in the selecionarEmitente() method, the object localidade is null. If I made the set on the dataTable page and the name of the selected object appears on the secondPage, what is missing?

I already researched other posts about this problem. For example, according to this post, my javabeans involved have the equals() and hashCode() methods. Unlike this other post, I'm using custom converters.

Where is my mistake?

I'm using RichFaces 4.5.1.Final, MyFaces 2.2.10, Spring 3.1.1 .

dataTable.xhtml

<h:selectOneMenu id="estado"
    immediate="true" validator="#{validadorMB.validarEstado}"
    converter="estadoConverter">
    <f:selectItem itemLabel="---" />
    <f:selectItems value="#{localidadeMB.estados}"
                   var="est" itemValue="#{est}" itemLabel="#{est.uf}" />
    <a4j:ajax event="change" actionListener="#{localidadeMB.filtrarUF}" render="table" />
</h:selectOneMenu>

<a4j:region id="region" immediate="true">
    <rich:dataTable id="tabela"
        value="#{localidadeMB.getLocalidadesPorUF()}" var="loc"
        rowKeyVar="row" rows="20" width="800px" render="scroller">
        <rich:column id="col_localidade" sortBy="#{loc.nome}" filterBy="#{loc.nome}">
            <h:outputText id="nomeLocalidade" value="#{loc.nome}" />
        </rich:column>
        ...
        <rich:column>
            <h:commandLink id="declaracaolink" action="#{localidadeMB.carregarLocalidade}">
                <h:graphicImage url="/img/declaracao.png" />
                <f:setPropertyActionListener value="#{loc}" target="#{localidadeMB.localidade}" />
            </h:commandLink>
        </rich:column>
    </rich:dataTable>
</a4j:region>

secondPage.xhtml

<h:body>
    <h:form id="formDeclaracao" focus="estado">
        <h:panelGrid columns="2" columnClasses="labelFormulario">
            <h:outputLabel value="UF" for="estado" />
            <h:selectOneMenu id="estado"
                value="#{localidadeMB.localidade.estado}"
                label="#{localidadeMB.localidade.estado.uf}"
                valueChangeListener="#{localidadeMB.selecionarEstado}"
                validator="#{validadorMB.validarEstado}" immediate="true"
                converter="estadoConverter"
                style="width: 45px;" styleClass="listbox">
                <f:selectItems value="#{localidadeMB.estados}"
                       var="est" itemValue="#{est}" itemLabel="#{est.uf}" />
                <a4j:ajax event="change" render="nomeLocalidade" />
            </h:selectOneMenu>

            <h:outputLabel value="Nome da localidade:" for="nomeLocalidade" />
            <h:selectOneMenu id="nomeLocalidade"
                value="#{localidadeMB.localidade}"
                label="#{localidadeMB.localidade.nome}" immediate="true"
                valueChangeListener="#{localidadeMB.selecionarLocalidade}"
                validator="#{validadorMB.validarLocalidade}"
                converter="localidadeConverter"
                style="width: 220px;" styleClass="listbox">
                <f:selectItems value="#{localidadeMB.localidades}"
                     var="loc" itemValue="#{loc}" itemLabel="#{loc.nome}" />
            </h:selectOneMenu>

            <h:outputLabel value="Interessado:" for="interessado" />
            <h:inputText id="interessado" value="" required="true"
                requiredMessage="xxxxxxxxx" immediate="true"
                styleClass="listbox" style="width: 215px;">
            </h:inputText>

            <h:outputLabel value="Solicitante:" for="solicitante" />
            <h:inputText id="solicitante" value="" required="true"
                requiredMessage="xxxxxxxxxxxxx" immediate="true">
            </h:inputText>

            <h:outputLabel value="Documento apresentado:" for="documento" />
            <h:inputText id="documento" value="" required="true"
                requiredMessage="xxxxxxxxxxxxx" immediate="true">
            </h:inputText>

            <h:outputLabel value="Emitente:" for="emitente" />
            <h:selectOneMenu id="emitente"
                value="#{localidadeMB.emitente}"
                label="#{localidadeMB.emitente.descricaoReduzida}"
                valueChangeListener="#{localidadeMB.selecionarEmitente}"
                validator="#{validadorMB.validarEmitente}"
                converter="emitenteConverter">
                <f:selectItem itemLabel="---" />
                <f:selectItems value="#{localidadeMB.emitentes}" var="em" itemValue="#{em}" itemLabel="#{em.descricaoReduzida}" />
            </h:selectOneMenu>

            <h:commandButton id="btnGerarDeclaracao" value="Get PDF"
                action="#{localidadeMB.getPDF()}" style="width: 84px;" />
        </h:panelGrid>
    </h:form>
</h:body>

ManagedBean

@ManagedBean
public class LocalidadeMB{
    private Emitente emitente;
    private Estado estado;
    private Localidade localidade;

    public String carregarLocalidade() {
        estado = localidade.getEstado();
        localidade = getLocalidade();
        getLocalidades();
        carregarLocalidadePorUF(estado);
        return "secondPage.xhtml";
    }

    public void filtrarUF(ActionEvent action) {
        try {
            String uf = JSFHelper.getRequestParameter("formConsulta"
                + UINamingContainer.getSeparatorChar(JSFHelper
                    .getFacesContext()) + "estado");
            estado = estadoFacade.getEstado(Integer.parseInt(uf));
        } catch (Exception e) {
            ...
        }
    }

    public List<Emitente> getEmitentes() {
        try {
            return emitenteFacade.getEmitentes();
        } catch (Exception e) {
            ...
        }
    }

    public List<Emitente> getEstados() {
        try {
            return estadoFacade.getEstados();
        } catch (...) {
           ...
        }
    }

    public List<Localidade> getLocalidades() {
        try {
            return localidadeFacade.getLocalidades();
        } catch (Exception e) {
            ...
        }
    }

    public List<Localidade> getLocalidadesPorUF() {
        try {
            String uf = JSFHelper.getRequestParameter("formConsulta"
                + UINamingContainer.getSeparatorChar(JSFHelper
                        .getFacesContext()) + "estado");
            if ((uf != null) && (!uf.equals("---"))) {
                estado = estadoFacade.getEstado(Integer.parseInt(uf));
                return localidadeFacade.getLocalidadesPorEstado(estado);
            } else {
                return null;
            }
        } catch (Exception e) {
            ...
        }
    }


    public void selecionarEmitente(ValueChangeEvent evento) {
        emitente = (Emitente)evento.getNewValue();
    }

    public void selecionarEstado(ValueChangeEvent evento) {
        estado = (Estado)evento.getNewValue();
    }

    public void selecionarLocalidade(ValueChangeEvent evento) {
        localidade = (Localidade)evento.getNewValue();
    }
}

Validator

@ManagedBean(name = "validadorMB")
public class ValidadorLocalidadeMB {
    public void validarEmitente(FacesContext context, UIComponent componentToValidate, Object value) throws ValidatorException {
        if (((Emitente) value).getEmitenteId() == 0) {  
            FacesMessage msg = new FacesMessage(null, "Selecione o emitente");
            throw new ValidatorException(msg);
        }
    }

    public void validarEstado(FacesContext context, UIComponent componentToValidate, Object value) throws ValidatorException {
        if (((Estado) value).getEstadoId() == 0) {  
            FacesMessage msg = new FacesMessage(null, "Selecione uma UF");
            throw new ValidatorException(msg);
        }
    }

    public void validarLocalidade(FacesContext context, UIComponent componentToValidate, Object value) throws ValidatorException {
        if (((Localidade) value).getLocalidadeId() == 0) {  
            FacesMessage msg = new FacesMessage(null, "Selecione uma localidade");
            throw new ValidatorException(msg);
        }
    }
}

Converters

@FacesConverter(value = "emitenteConverter")
public class EmitenteConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent ui, String value) throws ConverterException {
        ValueExpression vex = context
            .getApplication()
            .getExpressionFactory()
            .createValueExpression(context.getELContext(),
                    "#{emitenteFacade}", EmitenteFacadeImpl.class);

        EmitenteFacadeImpl fac = (EmitenteFacadeImpl) vex.getValue(context
            .getELContext());
        try {
            return fac.getEmitentePorId(Integer.valueOf(value));
        } catch (NumberFormatException | DAOException e) {
         ....
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent ui, Object value) throws ConverterException {
        if (value == null) {
            return "";
        }

        if (value instanceof Emitente) {
            return String.valueOf(((Emitente) value).getEmitenteId());
        }
    }
}

@FacesConverter(value = "estadoConverter")
public class EstadoConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent ui, String value) throws ConverterException {
        ValueExpression vex = context
            .getApplication()
            .getExpressionFactory()
            .createValueExpression(context.getELContext(),
                    "#{estadoFacade}", EstadoFacadeImpl.class);

        EstadoFacadeImpl fac = (EstadoFacadeImpl) vex.getValue(context
            .getELContext());
        try {
            return fac.getEstadoPorId(Integer.valueOf(value));
        } catch (NumberFormatException | DAOException e) {
         ....
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent ui, Object value) throws ConverterException {
        if (value == null) {
            return "";
        }

        if (value instanceof Estado) {
            return String.valueOf(((Estado) value).getEstadoId());
        }
    }
}

@FacesConverter(value = "localidadeConverter")
public class LocalidadeConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent ui, String value) throws ConverterException {
        ValueExpression vex = context
            .getApplication()
            .getExpressionFactory()
            .createValueExpression(context.getELContext(),
                    "#{localidadeFacade}", LocalidadeFacadeImpl.class);

        LocalidadeFacadeImpl fac = (LocalidadeFacadeImpl) vex.getValue(context.getELContext());
        try {
            return fac.getLocalidadePorId(Integer.valueOf(value));
        } catch (NumberFormatException | DAOException e) {
         ....
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent ui, Object value) throws ConverterException {
        if (value == null) {
            return "";
        }

        if (value instanceof Localidade) {
            return String.valueOf(((Localidade) value).getLocalidadeId());
        }
    }
}
Community
  • 1
  • 1
Rogério Arantes
  • 712
  • 1
  • 8
  • 29
  • Can you narrow down this question to one component? – Emil Sierżęga Jan 20 '17 at 21:02
  • You shouldn't have any business logic in the getters, though it's hard to say if that is the problem. – Makhiel Jan 23 '17 at 09:27
  • Sorry, Emil Sierzega, I did not understand your question. – Rogério Arantes Jan 23 '17 at 18:12
  • Makhiel, I personally do not believe that the problem is in the getter, since it is only constructing the SELECT elements. So much so that the select is perfectly displayed in HTML. – Rogério Arantes Jan 23 '17 at 18:16
  • The selected value is being compared to the select elements, that's where you get the error from. Besides the getter is called multiple times, it may not be returning the same values. – Makhiel Jan 24 '17 at 09:07
  • BalusC, you marked this post as repeated, but unlike the post linked by you, in my problem the error message doesn't display the component where is the error – Rogério Arantes Jan 31 '17 at 10:58

1 Answers1

1

Your problem might be with this line:

value="#{(localidadeMB.localidade.localidadeId != null) ? localidadeMB.localidade.localidadeId :localidadeMB.localidade}"

The value of a <h:selectOneMenu> should be a simple property, not an expression, as it has to set.


Edit:

There could be another problem with your code:

You construct those SelectItems with the entity's ID as the value property, and then use converter to convert String to/from the entity itself.

Thus there are a few possibilities for you:

  1. Use the converter, and the "whole" entity as the value of SelectItem.
  2. Or don't use Selectitems, but a List of the entities themselves, as your first link does.
  3. The other possibility is to use a dummy entity, set its id property, and in your valueChangeListener retrieve the entity by the ID.
Community
  • 1
  • 1
Usagi Miyamoto
  • 6,196
  • 1
  • 19
  • 33
  • Thank you, for your answer. I don't think there is this restriction, but following your suggestion, I deleted the expression and left the simple value (localidadeMB.localidade.localidadeId), but it didn't work. – Rogério Arantes Jan 23 '17 at 18:24
  • The value attribute is indeed wrong, but that would only manifest as a problem during update model values phase with exactly this error: `javax.el.PropertyNotWritableException: Illegal Syntax for Set Operation`. OP's concrete problem, however, already takes place during validations phase and yielded a completely different error. – BalusC Jan 24 '17 at 09:01
  • I changed the code following the suggestions, but the error remains. I changed the code and inserted the excerpts from another page, so that the context can be understood. – Rogério Arantes Jan 31 '17 at 13:29