验证错误:值无效 [英] Validation Error: Value is not valid

查看:127
本文介绍了验证错误:值无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a problem with a p:selectOneMenu, no matter what I do I cannot get JSF to call the setter on the JPA entity. JSF validation fails with this message:

form:location:验证错误:值无效

form:location: Validation Error: Value is not valid

我在同类型的其他几个类上工作(例如,联接表类),但是我一生都无法工作.

I have this working on several other class of the same type (ie, join table classes) but cannot for the life of me get this one working.

如果任何人都可以针对此类问题提出一些故障排除/调试提示,将不胜感激.

If anyone can throw some troubleshooting/debugging tips for this sort of problem it would be greatly appreciated.

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

Using log statements I have verified the following:

  1. Conveter返回正确的非null值.
  2. 我的JPA实体中没有Bean验证.
  3. 二传手setLocation(Location location)从未被调用.
  1. The Conveter is returning correct, non null values.
  2. I have no Bean Validation in my JPA entities.
  3. The setter setLocation(Location location) is never called.

这是我能做的最简单的例子,它根本行不通:

This is the simplest example I can do and it simply will not work:

<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>

转换器:

@FacesConverter(forClass=Location.class, value="locationConverter")
public class LocationConverter implements Converter, Serializable {
    private static final Logger logger = Logger.getLogger(LocationConverter.class.getName());

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value.isEmpty())
            return null;
        try {
            Long id = Long.parseLong(value);
            Location location = ((LocationManagedBean) context.getApplication().getELResolver().getValue(context.getELContext(), null, "location")).find(id);
            logger.log(Level.SEVERE, "Converted {0} to {1}" , new Object[] {value, location});
            return location;
        } catch (NumberFormatException e) {
            return new Location();
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (value == null || value.toString().isEmpty() || !(value instanceof Location))
            return "";
        return String.valueOf(((Location) value).getId());
    }    
}

控制台输出:

// 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] 

推荐答案

验证失败,并显示消息"form:location:验证错误:值无效"

此错误归结为选定的项目与表单提交请求处理期间由任何嵌套的<f:selectItem(s)>标记指定的任何可用选择项目值都不匹配.

This error boils down to that the selected item does not match any of the available select item values specified by any nested <f:selectItem(s)> tag during processing of the form submit request.

作为防范篡改/被入侵请求的一部分,JSF将重申所有可用的选择项值,并测试selectedItem.equals(availableItem)对于至少一个可用项值是否返回true.如果没有一个项目值匹配,那么您将确切地得到此验证错误.

As part of safeguard against tampered/hacked requests, JSF will reiterate over all available select item values and test if selectedItem.equals(availableItem) returns true for at least one available item value. If no one item value matches, then you'll get exactly this validation error.

此过程基本上是以下内容,其中bean.getAvailableItems()虚构地表示了<f:selectItem(s)>定义的可用选择项的整个列表:

This process is under the covers basically as below, whereby bean.getAvailableItems() fictionally represents the entire list of available select items as defined by <f:selectItem(s)>:

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");
}

因此,根据上述逻辑,此问题在逻辑上可以至少具有以下原因:

So, based on the above logic, this problem can logically have at least the following causes:

  1. 可用项目列表中缺少所选项目.
  2. 表示所选项目的类的equals()方法丢失或损坏.
  3. 如果涉及到自定义Converter,则它在getAsObject()中返回了错误的对象.也许甚至是null.
  1. The selected item is missing in the list of available items.
  2. The equals() method of the class representing the selected item is missing or broken.
  3. If a custom Converter is involved, then it has returned the wrong object in getAsObject(). Perhaps it's even null.

要解决它:

  1. 确保在后续请求期间保留完全相同的列表,尤其是在多个级联菜单的情况下.在大多数情况下,将豆做成@ViewScoped而不是@RequestScoped应该可以解决它.还要确保不要在<f:selectItem(s)>的getter方法中执行业务逻辑,而是在@PostConstruct或操作事件(侦听器)方法中执行业务逻辑.如果您依赖特定的请求参数,则需要将其显式存储在@ViewScoped bean中,或者通过例如以下方式在后续请求中重新传递它们<f:param>.另请参见如何选择正确的bean作用域?
  2. 确保正确实施equals()方法.这已经在标准Java类型(例如java.lang.Stringjava.lang.Number等)上正确完成了,但不一定要在自定义对象/bean/实体上进行.另请参见实现平等合同的正确方法.如果您已经在使用String,请确保正确配置了请求字符编码.如果它包含特殊字符并且JSF已配置为将输出呈现为UTF-8,但将输入解释为例如ISO-8859-1,那么它将失败.另请参阅通过PrimeFaces输入组件检索的Unicode输入已损坏.
  3. 调试/记录自定义Converter的操作,并相应地进行修复.有关准则,另请参见空转换器"的转换错误设置值,如果您将java.util.Date用作<f:convertDateTime>,请确保您不会忘记模式中的全职工作.另请参见>验证错误:值无效".来自f:datetimeConverter 的错误.
  1. Ensure that exactly the same list is been preserved during the subsequent request, particularly in case of multiple cascading menus. Making the bean @ViewScoped instead of @RequestScoped should fix it in most cases. Also make sure that you don't perform the business logic in the getter method of <f:selectItem(s)>, but instead in @PostConstruct or an action event (listener) method. If you're relying on specific request parameters, then you'd need to explicitly store them in the @ViewScoped bean, or to re-pass them on subsequent requests by e.g. <f:param>. See also How to choose the right bean scope?
  2. Ensure that the equals() method is implemented right. This is already done right on standard Java types such as java.lang.String, java.lang.Number, etc, but not necessarily on custom objects/beans/entites. See also Right way to implement equals contract. In case you're already using String, make sure that the request character encoding is configured right. If it contains special characters and JSF is configured to render the output as UTF-8 but interpret the input as e.g. ISO-8859-1, then it will fail. See also a.o. Unicode input retrieved via PrimeFaces input components become corrupted.
  3. Debug/log the actions of your custom Converter and fix it accordingly. For guidelines, see also Conversion Error setting value for 'null Converter' In case you're using java.util.Date as available items with <f:convertDateTime>, make sure that you don't forget the full time part in the pattern. See also "Validation Error: Value is not valid" error from f:datetimeConverter.

另请参见:

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆