JSF SelectOneMenu 与 noSelectionOption 使用标签作为值?

发布于 2024-10-10 10:37:31 字数 3352 浏览 6 评论 0原文

在“创建新用户”jsf 页面中,我有一个带有自定义转换器的 SelectOneMenu 和一个 noSelectionOption selectItem,如下所示:(省略无关代码)

NewUser.xhtml

<h:form>
<h:selectOneMenu value="#{newUserController.user.department}" 
                 required="true" converter="departmentConverter">
    <f:selectItem itemLabel="Select a department" noSelectionOption="true"/>
    <f:selectItems value="#{newUserController.departments}"
                   var="dep" itemLabel="#{dep.name}" itemValue="#{dep}"/>
</h:selectOneMenu>
<p:commandButton action="#{newUserController.saveUser}"
                 value="#{bundle.Save}"
                 ajax="false"/>
</h:form>

NewUserController.java

@ManagedBean
@ViewScoped
public class NewUserController implements Serializable {
private static final long serialVersionUID = 10L;

@EJB private UserBean userBean;
private List<Department> departments;
private User user;

public NewUserController () {
}

@PostConstruct
public void init(){
    user = new User();
    departments = userBean.findAllDepartments();
}

public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}

public List<Department> getDepartments(){
    return departments;
}

public String saveUser() {
    // Business logic
}
}

DepartmentConverter.java

@FacesConverter(value="departmentConverter")
public class DepartmentConverter extends EntityConverter {
    public DepartmentConverter(){
        super(Department.class);
    }
}

适用于所有实体的超级转换器

public class EntityConverter<E> implements Converter{
protected Class<E> entityClass;

public EntityConverter(Class<E> type) {
    entityClass = type;
}

@Override
public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
    if (value == null || value.length() == 0) {
        return null;
    }
    try {
        InitialContext ic = new InitialContext();
        UserBean ub = (UserBean)ic.lookup("java:global/CompetenceRegister/UserBean");
        return ub.find(entityClass, getKey(value));
    } catch (NamingException e) {
        return null;
    }
}

Long getKey(String value) {
    Long key;
    key = Long.valueOf(value);
    return key;
}

String getStringKey(Long value) {
    StringBuilder sb = new StringBuilder();
    sb.append(value);
    return sb.toString();
}

@Override
public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
    if (object == null) {
        return null;
    }
    if (object instanceof AbstractEntity) {
        AbstractEntity e = (AbstractEntity) object;
        return getStringKey(e.getId());
    }
    else
        throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + entityClass.getName());
}

}

但是,当我发布时选择“选择部门”选项的表单,它将 label 发送到转换器中的 getAsObject 而不是 null,从而导致转换器在 getKey 中抛出异常(尝试转换包含id 为 Long)。将 selectItem 的 itemValue 属性设置为 null 无效。该系列中的物品与转换器完美配合。有谁知道是什么原因造成的?

更新 一件有趣的事情我忘了提;如果我从 SelectOneMenu 中删除转换器属性,则 noSelectionAttribute 会按其应有的方式工作,但由于默认转换器不知道如何转换我的对象,因此帖子无法选择真正的部门。这是否意味着 noSelectionOption=true SUPPOSED 会发送其标签,并且转换器应该以某种方式处理它?

In a "create new user" jsf page, I have a SelectOneMenu with a custom converter and a noSelectionOption selectItem like this: (irrelevant code ommited)

NewUser.xhtml

<h:form>
<h:selectOneMenu value="#{newUserController.user.department}" 
                 required="true" converter="departmentConverter">
    <f:selectItem itemLabel="Select a department" noSelectionOption="true"/>
    <f:selectItems value="#{newUserController.departments}"
                   var="dep" itemLabel="#{dep.name}" itemValue="#{dep}"/>
</h:selectOneMenu>
<p:commandButton action="#{newUserController.saveUser}"
                 value="#{bundle.Save}"
                 ajax="false"/>
</h:form>

NewUserController.java

@ManagedBean
@ViewScoped
public class NewUserController implements Serializable {
private static final long serialVersionUID = 10L;

@EJB private UserBean userBean;
private List<Department> departments;
private User user;

public NewUserController () {
}

@PostConstruct
public void init(){
    user = new User();
    departments = userBean.findAllDepartments();
}

public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}

public List<Department> getDepartments(){
    return departments;
}

public String saveUser() {
    // Business logic
}
}

DepartmentConverter.java

@FacesConverter(value="departmentConverter")
public class DepartmentConverter extends EntityConverter {
    public DepartmentConverter(){
        super(Department.class);
    }
}

Super converter for all entities

public class EntityConverter<E> implements Converter{
protected Class<E> entityClass;

public EntityConverter(Class<E> type) {
    entityClass = type;
}

@Override
public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
    if (value == null || value.length() == 0) {
        return null;
    }
    try {
        InitialContext ic = new InitialContext();
        UserBean ub = (UserBean)ic.lookup("java:global/CompetenceRegister/UserBean");
        return ub.find(entityClass, getKey(value));
    } catch (NamingException e) {
        return null;
    }
}

Long getKey(String value) {
    Long key;
    key = Long.valueOf(value);
    return key;
}

String getStringKey(Long value) {
    StringBuilder sb = new StringBuilder();
    sb.append(value);
    return sb.toString();
}

@Override
public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
    if (object == null) {
        return null;
    }
    if (object instanceof AbstractEntity) {
        AbstractEntity e = (AbstractEntity) object;
        return getStringKey(e.getId());
    }
    else
        throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + entityClass.getName());
}

}

However, when i post the form with the "Select a department" option chosen, it sends the label to getAsObject in the converter instead of null, thus causing the converter to throw an exception in getKey (tries to convert a String containing an id to a Long). Setting the itemValue attribute of the selectItem to null has no effect. The items from the collection works perfectly otherwise with the converter. Does anyone have any idea of what is causing this?

Update An interesting thing I forgot to mention; if I remove the converter attribute from the SelectOneMenu, the noSelectionAttribute works as it should, but since the default converter doesn't know how to convert my objects, the post fails on selecting a true department instead. Can this mean that the noSelectionOption=true is SUPPOSED to send its label instead and the converter is somehow expected to handle it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

轻拂→两袖风尘 2024-10-17 10:37:31

我的问题是切换到使用 SelectOneMenu 的转换器属性,而不是使用 FacesConverter 的 forClass 属性。

切换

@FacesConverter(value="departmentConverter")
public class DepartmentConverter extends EntityConverter {
public DepartmentConverter(){
    super(Department.class);
}
}

@FacesConverter(forClass=Department.class)
public class DepartmentConverter extends EntityConverter {
public DepartmentConverter(){
    super(Department.class);
}
}

导致我自己的转换器用于实际值,而当 NoSelectionOption 属性设置为 true 时,使用默认转换器(空转换器?我无法找到它的源代码)。我的理论是,将此属性设置为 true 会将值的类型设置为 null,并将标签作为值,导致它转到始终返回 null 或类似内容的特殊转换器。使用转换器属性而不是 forClass 会导致我自己的转换器始终被使用,无论类型如何,因此我必须自己处理作为值发送的标签。

My problem was switching to using the converter attribute of SelectOneMenu instead of using the forClass attribute of FacesConverter.

switching

@FacesConverter(value="departmentConverter")
public class DepartmentConverter extends EntityConverter {
public DepartmentConverter(){
    super(Department.class);
}
}

to

@FacesConverter(forClass=Department.class)
public class DepartmentConverter extends EntityConverter {
public DepartmentConverter(){
    super(Department.class);
}
}

causes my own converter to be used for real values while the default converter (null converter? I have not been able to find the source code for it) is used when the NoSelectionOption attribute is set to true. My theory is that setting this attribute to true sets the type of the value to null with the label as value causing it to go to a special converter always returning null or something similar. Using the converter attribute instead of forClass causes my own converter to always be used regardless of type, and I would thus have to handle the label being sent as value myself.

梦开始←不甜 2024-10-17 10:37:31

一种可行的解决方案是简单地添加

try{
    return ub.find(entityClass, getKey(value));
}catch(NumberFormatException e){ // Value isn't a long and thus not an id.
    return null;
}

到 EntityConverter 中的 getAsObject,但这感觉就像我在错误的位置修复了问题。将标签作为值发送根本没有意义,它实际上应该发送 NULL。

One solution that works is to simply add

try{
    return ub.find(entityClass, getKey(value));
}catch(NumberFormatException e){ // Value isn't a long and thus not an id.
    return null;
}

to the getAsObject in EntityConverter, but this feels like I am fixing the problem in the wrong place. Sending the label as value simply does not make sense, it should really send NULL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文