JSF转换器验证错误:对于SelectOneMenu UI组件,值无效。

10

我正在使用请求范围中的managedBean userHome,其中实体'user'将被保存。用户具有映射到ManyToOne关系的leader列。我的代码如下:

@ManagedBean
@RequestScoped
public class UserHome {
    private User user = new User();
        // Getters and Setters

    private List<SelectItem> selectItems = new ArrayList<SelectItem>();

    public UserHome() {
        for(User user: availableLeaders) {
            selectItems.add(new SelectItem(user.getName(), user));
        }
    }

    public void persis();
}

User.java

public class User {
    @Id
    @Column
    private Integer id;

    @Column
    privat String name;

    @ManyToOne
    private User leader;
}

我正在尝试通过h:selectOneMenu来获取此领导者的值,就像这样:

<h:selectOneMenu value="#{userHome.user.leader}" converter="userConverter">
    <f:selectItems value="#{userHome.selectItems}"/>
</h:selectOneMenu>

我的转换器长这样

@FacesConverter(forClass = User.class, value="userConverter")
public class UserConverter implements Converter {

    private  Map<String, User> userValues = new HashMap<String, User>();

    public UserConverter() {
        init();
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component,
            String value) {
        return userValues.get(value);
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        System.out.println("RAJASEKARAN "+value);
        return ((User)value).getName();
    }

    public void init() {
        UserHome userHome = new UserHome();
        for(User user:userHome.availableLeaders()) {
            userValues.put(user.getName(), user);
        }
    }
}
尝试保存用户时,出现错误UserEdit:j_idt18:验证错误:值无效。
2个回答

14

补充BalusC的回答:在回传之后,您需要确保User实例与用于渲染选择项的实例完全相同,或者为您的User类实现equals方法。

代码没有显示availableLeaders来自何处,但如果这是按需从数据库中获取的,则转换器将无法将其转换为JSF通过#{userHome.selectItems}解析的列表中具有相同对象实例的实例。

转换后,JSF将使用equals()方法检查是否可以在该列表中找到转换后的实例。


嗨,这个等于检查发生在mojarra代码的哪里?我正在编写一个自定义组件,遇到了这个问题,我想调试mojarra代码以查看发生了什么。谢谢。 - Thang Pham
这发生在 UISelectMany#validateValue 中,实际调用 equals 发生在 SelectUtils#matchValue 中。 - Arjan Tijms
经过大量的调试,我终于弄清楚了这个问题。不验证是否算是一种不好的做法吗?我的自定义组件是从UISelectOne扩展而来的,而这个validateValue方法给了我很多烦恼。如果我用空内容覆盖这个方法,那么事情就能正常工作。但我有一种感觉,这是我不应该做的事情。你有什么想法吗? - Thang Pham
1
不允许进行检查会使您面临类似于批量赋值漏洞在Github上发生的攻击(请参见http://www.infoq.com/news/2012/03/GitHub-Compromised)。 - Arjan Tijms
谢谢您!经过一些思考,我想我有一个关于如何使验证工作的想法。感谢您的帮助。 - Thang Pham
不用谢。你可能还想看一下:http://showcase-omnifaces.rhcloud.com/showcase/converters/SelectItemsConverter.xhtml 这个示例使用原始列表进行比较。如果它来自例如视图范围,并且没有进行任何序列化(Mojarra的默认值),则“equals”将为真,无需做任何事情。 - Arjan Tijms

8
您构造了SelectItem的方式是错误的。根据类的文档,第一个参数应该表示项目值(需要转换和提交),第二个参数应该表示项目标签(需要在列表中显示)。但是您把它们指定反了。
请相应地进行修复:
selectItems.add(new SelectItem(user, user.getName()));

如果这仍然不能解决问题,那么就意味着User类的equals()方法没有被(正确)实现。JSF将使用它来验证选定的User是否与转换后的列表项值匹配。
与具体问题无关,JSF2中的<f:selectItems>提供了一种构建列表的可能性,而不需要手动构建SelectItem列表。以下是一个完全相同的示例:
<f:selectItems value="#{userHome.availableLeaders}" var="user" 
    itemValue="#{user}" itemLabel="#{user.name}" />

这使您可以摆脱额外的selectItems属性和bean构造函数中的循环。

1
+1,将SelectItem类型从后端Bean中剥离出来,并使用简单的域对象列表。 - Arjan Tijms

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接