Validation 验证错误:值无效

Validation 验证错误:值无效,validation,jsf,jpa,converter,selectonemenu,Validation,Jsf,Jpa,Converter,Selectonemenu,我对p:selectOneMenu有一个问题,无论我做什么,我都无法让JSF调用JPA实体上的setter。JSF验证失败,并显示以下消息: 表单:位置:验证错误:值无效 我在其他几个相同类型的类(即join table类)上也做了这个工作,但我一辈子都不能让这个工作 如果有人能为此类问题提供一些故障排除/调试技巧,我们将不胜感激 我使用日志语句验证了以下内容: 转换器正在返回正确的非空值。 我的JPA实体中没有Bean验证。 从未调用setter setLocation位置。 这是我能做的最简

我对p:selectOneMenu有一个问题,无论我做什么,我都无法让JSF调用JPA实体上的setter。JSF验证失败,并显示以下消息:

表单:位置:验证错误:值无效

我在其他几个相同类型的类(即join table类)上也做了这个工作,但我一辈子都不能让这个工作

如果有人能为此类问题提供一些故障排除/调试技巧,我们将不胜感激

我使用日志语句验证了以下内容:

转换器正在返回正确的非空值。 我的JPA实体中没有Bean验证。 从未调用setter setLocation位置。 这是我能做的最简单的例子,但它根本不起作用:

<h:body>
    <h:form id="form">
        <p:messages id="messages" autoUpdate="true" />
        <p:selectOneMenu id="location" value="#{locationStockList.selected.location}" converter="locationConverter">
            <p:ajax event="change" update=":form:lblLocation"/>
            <f:selectItems value="#{locationStockList.locationSelection}"/>
        </p:selectOneMenu>
    </h:form>
</h:body>
控制台输出:

// Getter method
INFO: Current value=ejb.locations.Location[id=null, name=null, latitude=0.0, longitude=0.0] 
// Session Bean
INFO: Finding ejb.locations.Location with id=3 
// Session Bean
INFO: ### Returning : ejb.locations.Location[id=3, name=mdmd, latitude=4.5, longitude=2.3] 
// Converter
SEVERE: Converted 3 to ejb.locations.Location[id=3, name=mdmd, latitude=4.5, longitude=2.3] 
// Getter method -> Where did my selected Location go ??
INFO: Current value=ejb.locations.Location[id=null, name=null, latitude=0.0, longitude=0.0] 
验证失败,消息形式为:位置:验证错误:值无效

此错误归结为,在处理表单提交请求期间,所选项目与任何嵌套标记指定的任何可用选择项目值都不匹配

作为防止篡改/黑客请求的一部分,JSF将对所有可用的select item值进行重申,并测试selectedItem.equalsavailableItem是否对至少一个可用的item值返回true。如果没有一个项值匹配,那么您将得到这个验证错误

该过程的基本内容如下所示,其中bean.getAvailableItems虚拟地表示可用选择项的整个列表,定义如下:

因此,基于上述逻辑,该问题在逻辑上至少有以下原因:

可用项列表中缺少选定项。 表示选定项的类的equals方法缺失或已损坏。 如果涉及自定义转换器,则它在getAsObject中返回了错误的对象。也许它甚至是空的。 要解决这个问题:

确保在后续请求期间保留完全相同的列表,特别是在多个级联菜单的情况下。在大多数情况下,将bean设置为@viewscope而不是@requestscope应该可以解决这个问题。还要确保不在的getter方法中执行业务逻辑,而是在@PostConstruct或动作事件侦听器方法中执行业务逻辑。如果您依赖于特定的请求参数,那么您需要将它们显式地存储在@ViewScoped bean中,或者在后续请求中通过例如重新传递它们。另见 确保equals方法的实现是正确的。这已经在标准Java类型(如Java.lang.String、Java.lang.Number等)上正确地完成了,但不一定在自定义对象/bean/Entite上完成。另见。如果您已经在使用字符串,请确保请求字符编码配置正确。如果它包含特殊字符,并且JSF被配置为将输出呈现为UTF-8,但将输入解释为例如ISO-8859-1,那么它将失败。另见a.o。 调试/记录自定义转换器的操作,并相应地进行修复。有关指导原则,请参见在使用java.util.Date作为可用项的情况下,确保不要忘记模式中的全职部分。另见。 另见: 如果有人能为此类问题提供一些故障排除/调试技巧,我们将不胜感激


请在这里提出一个明确而具体的问题。不要问太宽泛的问题

在我的例子中,我忘了实现正确的get/set方法。这是因为我在开发过程中改变了很多属性

如果没有合适的get方法,JSF将无法恢复您选择的项,并且会发生BalusC在其回答的第1项中所说的情况:

一,。可用项列表中缺少选定项。如果可用项列表由请求范围的bean提供服务,而该bean在后续请求中没有正确地重新初始化,或者在getter方法中错误地执行业务作业,从而导致它以某种方式返回不同的列表,则可能会发生这种情况


这可能是转换器问题或DTO问题。 尝试通过在对象DTO中添加hashCode和equals方法来解决这个问题;在上面的场景中,您可以在Location对象类中生成这些方法,在这里表示为“DTO”

例如:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (int) (id ^ (id >>> 32));
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Location other = (Location) obj;
    if (id != other.id)
        return false;
    return true;
}
请注意,上面的示例是针对“long”类型的“id”。
@巴卢斯克:在莫哈拉代码中,这等于检查发生了什么。我的情况有点复杂。我创建了自己的自定义组件,允许用户拥有复杂的无线电布局。如果我只有一个收音机组f:selectItems,它就可以在我的自定义组件下面正常工作。但是,随着布局变得越来越复杂,多个无线电组中的每个组都有自己的f:selectItems,但所有组都共享相同的选择,我必须在ui:repeat中包含f:selectItems,然后ui:repeat位于我的自定义组件下。然后我遇到了这个问题。我想看看处理这个问题的mojarra代码,还有我的f:selectI
tems是字符串类型,所以我确信这不是转换问题,我认为这是原因,因为在验证阶段f:selectItems列表不存在。您能否详细说明如何使用f:param向托管bean发送状态,以便它可以重新创建初始状态???谢谢。有一个类似的错误。我使用的是,该组件位于禁用的字段集中,因此它也被禁用。这是一种已知的行为吗?如果您使用enum来显示项,并且您的支持bean具有字符串类型来设置bean中的值,并且不使用任何转换器,那么您将得到相同的错误。这就是我在这里结束的原因。就像在第2条中所说的,在被接受的和高度投票的答案中
String submittedValue = request.getParameter(component.getClientId());
Converter converter = component.getConverter();
Object selectedItem = (converter != null) ? converter.getAsObject(context, component, submittedValue) : submittedValue;

boolean valid = false;

for (Object availableItem : bean.getAvailableItems()) {
    if (selectedItem.equals(availableItem)) {
        valid = true;
        break;
    }
}

if (!valid) {
    throw new ValidatorException("Validation Error: Value is not valid");
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (int) (id ^ (id >>> 32));
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Location other = (Location) obj;
    if (id != other.id)
        return false;
    return true;
}