【问题标题】:JSF Validation Error: Value is not valid [duplicate]JSF 验证错误:值无效 [重复]
【发布时间】:2011-09-13 12:32:45
【问题描述】:

我知道这似乎很常见,但我对此感到迷茫。在单击assessment.jsf 中的添加按钮时发生。无论如何,我附上了我认为相关的部分。

FWIW,AssessmentType.equals() 在我调试时没有被触发。

提前致谢。

j_idt38:j_idt47:j_idt48: Validation Error: Value is not valid

评估.xhtml:

        <h:form>
            <h:selectOneMenu value="#{assessmentBean.assessmentField}">
                <f:selectItems value="#{assessmentBean.assessment.type.fields}" />
            </h:selectOneMenu>

            <h:commandButton value="Add" action="#{assessmentBean.doAddField}">
                <f:param name="assessmentId"
                    value="#{assessmentBean.assessment.id}" />
            </h:commandButton>
        </h:form>

assessment.jsf:

<form id="j_idt38:j_idt47" name="j_idt38:j_idt47" method="post" action="/jsf-web/edit/assessment.jsf" enctype="application/x-www-form-urlencoded"> 
<input type="hidden" name="j_idt38:j_idt47" value="j_idt38:j_idt47" /> 
<select name="j_idt38:j_idt47:j_idt48" size="1">    <option value="1">Presenting Condition</option> 
    <option value="2">Problem Duration</option> 
</select> 
<script type="text/javascript" src="/jsf-web/javax.faces.resource/jsf.js.jsf?ln=javax.faces"></script>
<input type="submit" name="j_idt38:j_idt47:j_idt50" value="Add" onclick="mojarra.jsfcljs(document.getElementById('j_idt38:j_idt47'),{'j_idt38:j_idt47:j_idt50':'j_idt38:j_idt47:j_idt50','assessmentId':'1'},'');return false" /><input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="3431661972220941645:6952134510589038883" autocomplete="off" /> 
</form> 

AssessmentType.java:

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotNull;

import lombok.Data;

import org.hibernate.envers.Audited;

@Audited
@Data
@Entity
public class AssessmentType implements Comparable<AssessmentType> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    private String name;

    @OneToMany( fetch=FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=AssessmentField.class )
    private List<AssessmentField> fields;

    @Override
    public int compareTo(final AssessmentType o) {
        return getId().compareTo(o.getId());
    }

    @Override
    public String toString() {
        return getName();
    }
}

AssessmentFieldConverter.java

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.htu.fizio.api.AssessmentFieldManager;
import com.htu.fizio.domain.AssessmentField;

@FacesConverter(forClass = AssessmentField.class)
public class AssessmentFieldConverter implements Converter {

    AssessmentFieldManager<AssessmentField> assessmentFieldManager;

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public Object getAsObject(FacesContext ctx, UIComponent component, String value) {
        try {
            final InitialContext ic = new InitialContext();

            assessmentFieldManager = (AssessmentFieldManager) ic.lookup("fizio/AssessmentFieldManagerImpl/local");

            return assessmentFieldManager.find(Long.valueOf(value));
        } catch (NamingException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public String getAsString(FacesContext ctx, UIComponent component, Object value) {
        return String.valueOf(((AssessmentField) value).getId());
    }
}

AssessmentBean.java

    import java.util.List;

    import javax.annotation.PostConstruct;
    import javax.ejb.EJB;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ManagedProperty;
    import javax.faces.bean.SessionScoped;

    import lombok.Getter;
    import lombok.Setter;

    import com.htu.fizio.api.AssessmentManager;
    import com.htu.fizio.domain.Assessment;
    import com.htu.fizio.domain.AssessmentField;
    import com.htu.fizio.domain.AssessmentFieldValue;
    import com.htu.fizio.jsf.faces.FacesUtil;

...    

@PostConstruct
public void init() {
    if (FacesUtil.containsKey("assessmentId")) {
        final Long id = Long.parseLong(FacesUtil.get("assessmentId"));

        assessment = assessmentManager.find(id);
    } else {
        assessment = new Assessment();
    }
}

    public String doAddField() {
        final AssessmentFieldValue value = new AssessmentFieldValue();

        value.setField(assessmentField);
        value.setValue("");

        assessment.getFieldValues().add(value);

        assessmentManager.save(assessment);

        return "/edit/assessment";
    }

编辑:

在调试的时候才注意到这个,有可能是嫌疑人吗?:

Daemon Thread [HandshakeCompletedNotify-Thread] (Suspended (exception ConcurrentModificationException)) 
    HashMap$EntryIterator(HashMap$HashIterator<E>).nextEntry() line: 793    
    HashMap$EntryIterator.next() line: 834  
    HashMap$EntryIterator.next() line: 832  
    SSLSocketImpl$NotifyHandshakeThread.run() line: 2214    

【问题讨论】:

  • ConcurrentModificationException 看起来很糟糕,但由于它位于守护线程中,因此不太可能在问题的原始部分描述的级别上干扰 JSF。

标签: java jsf jboss jboss6.x mojarra


【解决方案1】:

验证错误:值无效

直言不讳,此错误意味着所选项目与列表中的任何可用项目都不匹配。 IE。由所选项目值表示的对象从未在其 equals() 调用中返回 true 以及任何可用的选择项目。

这个问题只有两个原因:

  1. 相关对象类型的equals() 方法已损坏。
  2. 项目列表的内容在表单提交请求的验证阶段与在显示表单的初始请求的呈现响应阶段不同。

由于第一个似乎已正确实施-根据 cmets-,剩下的唯一原因是第二个。假设您无法在 getter 方法中执行业务逻辑,一个简单的测试是将 #{assessmentBean} 放在会话范围内。如果可行,那么选择项列表的数据(预)加载逻辑肯定是错误的。

【讨论】:

  • 谢谢,但我无法到达 bean 会话范围的问题页面 - 首先它抱怨其他 bean 也需要会话范围,然后我在较早的页面上得到了这个:org. hibernate.TransientObjectException:对象引用了未保存的瞬态实例 - 在刷新之前保存瞬态实例:com.htu.fizio.domain.Appointment
  • @BalusC 我的equals() 可能发生什么样的问题使其无法正常工作?
  • @Daniel:如果它包含代码逻辑错误。
  • @BalusC 嗯...所以这不是我的问题,我猜。我有一个关于 JSF 的问题,如果可能的话,请看一下,它是关于转换器的
【解决方案2】:

验证失败,因为在您的转换器将 AssessmentType 的字符串表示形式转换回一个对象后,JSF 会迭代现有值 (assessmentBean.assessment.type.fields) 并将这个最近转换的对象与所有现有的对象进行比较。

由于你没有为AssessmentType实现Object#equals,它会默认为一个对象身份比较(粗略地说,你的对象的内存地址),这当然会失败。

因此解决方案是要么实现Object#equals,要么让转换器从assessmentBean.assessment.type.fields而不是AssessmentTypeManager获取对象。

【讨论】:

  • 我正在使用项目 lombok (@Data),它为我生成了一个 equals 方法,但即使我明确地实现了自己的方法断点,也不会触发它。这同样适用于 hashCode()。我不确定为什么AssessmentFieldManager 中的对象与assessmentBean.assessment.type.fields 中的对象类型不同,后者是List?道歉 - 刚刚意识到我已经粘贴了 AssessmentType 转换器而不是 AssessmentField 。
  • 我的错,对不起。此特定消息通常不是通过 ValidatorException 设置的,而是在 javax.faces.component.UISelectMany#validateValue 中设置的。您看到的消息很可能是来自 std JSF 资源包的javax.faces.component.UISelectMany.INVALID(它正是这个文本)。据我所知,此捆绑键仅在 UISelectMany 中使用。
  • 好的,但我们正在解决我认为的问题;)您也可以尝试javax.faces.component.UISelectOne#validateValue,因为文本也可以是javax.faces.component.UISelectOne.INVALID(这个实际上更有可能是您在 Facelet 上使用 h:selectOneMenu)。
  • 对于 JBoss AS 6,您不需要 javaee-6 的源代码,但对于 [jboss home]/server/default/deployers/jsf.deployer/Mojarra-2.0/jsf-libs/jsf -impl-2.0.3-b05.jar。不幸的是,JBoss 在提供完整源档案方面有点草率,所以您最好单独下载 Mojarra 2.0.3 (java.net/downloads/javaserverfaces/release/2.0.3/…)。如果你使用 Eclipse 和 JBoss 工具,上面提到的 jar 放在你的类路径中,并且源附件相对容易。
  • 如果 hasNext() 立即返回 null,很有可能assessmentBean.assessment.type.fields 确实返回了 null。在某些时候,JSF 会找到您的 f:selectItems 组件并评估它的值。找到它的最快方法是在 assesmentBean.getAssesment() 中设置断点,然后在 getType() 中,然后在 getFields 中。
【解决方案3】:

我想我已经解决了这个问题,至少,我已经进入下一个错误!

尽管发布了大量代码,但我没有发布完整的 xhtml,其中有多个嵌套的表单标签。只有一种形式似乎允许传递assessmentId 参数,这反过来又允许AssessmentBean 正确填充评估类型的AssessmentFields 列表。

感谢大家的帮助。

【讨论】:

    猜你喜欢
    • 2011-06-01
    • 2017-11-10
    • 2012-11-25
    • 2011-10-29
    • 2013-01-06
    • 2011-10-31
    • 2012-05-13
    • 2013-04-09
    相关资源
    最近更新 更多