“空转换器"的转换错误设置值-为什么在JSF中需要一个转换器? [英] Conversion Error setting value for 'null Converter' - Why do I need a Converter in JSF?

查看:124
本文介绍了“空转换器"的转换错误设置值-为什么在JSF中需要一个转换器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难理解如何在带有POJO/entity的JSF 2中有效使用选择.例如,我试图通过下面的下拉列表选择Warehouse实体:

<h:selectOneMenu value="#{bean.selectedWarehouse}">
    <f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
    <f:selectItems value="#{bean.availableWarehouses}" />
</h:selectOneMenu>

以及下面的托管bean:

@Named
@ViewScoped
public class Bean {

    private Warehouse selectedWarehouse;
    private List<SelectItem> availableWarehouses;

    // ...

    @PostConstruct
    public void init() {
        // ...

        availableWarehouses = new ArrayList<>();

        for (Warehouse warehouse : warehouseService.listAll()) {
            availableWarehouses.add(new SelectItem(warehouse, warehouse.getName()));
        }
    }

    // ...
}

请注意,我将整个Warehouse实体用作SelectItem的值.

我提交表单时,失败,并显示以下面孔消息:

空转换器"的转换错误设置值"com.example.Warehouse@cafebabe".

我希望JSF在将其包装在SelectItem中时,可以为托管bean设置正确的Warehouse对象.将我的实体包装在SelectItem内是为了跳过为我的实体创建Converter的过程.

我真的想在<h:selectOneMenu>中使用实体时真的要使用Converter吗?对于JSF,应该可以从可用项目列表中提取所选项目.如果我真的必须使用转换器,那么实际的操作方式是什么?到目前为止,我想到了这一点:

  1. 为实体创建Converter实现.
  2. 覆盖getAsString().我想我不需要这个,因为SelectItem的label属性将用于显示下拉选项标签.
  3. 覆盖getAsObject().我认为这将用于返回正确的SelectItem或实体,具体取决于托管bean中定义的所选字段的类型.

getAsObject()使我感到困惑.有效的方法是什么?具有字符串值,如何获取关联的实体对象?是否应该基于字符串值从服务对象中查询实体对象并返回该实体?或者也许我能以某种方式访问​​形成选择项的实体的列表,循环它们以找到正确的实体,然后返回该实体?

通常的做法是什么?

解决方案

简介

JSF生成HTML.用Java术语来说,HTML基本上是一个大的String.为了用HTML表示Java对象,必须将它们转换为String.另外,提交HTML表单时,在HTTP请求参数中将提交的值视为String.在幕后,JSF从 HttpServletRequest#getParameter() ,它返回String.

在非标准Java对象(即不是EL具有内置转换的StringNumberBoolean或JSF提供内置Date)之间进行转换. //docs.oracle.com/javaee/6/javaserverfaces/2.0/docs/pdldocs/facelets/f/convertDateTime.html"rel =" noreferrer> <f:convertDateTime> 标记),您确实必须提供一个自定义 Converter . SelectItem根本没有特殊用途.当无法提供例如JSF 1.x时,这只是JSF 1.x的一个遗留物. List<Warehouse>直接到<f:selectItems>.对于标签和转换,也没有特殊处理.

getAsString()

您需要实现

请注意,如果模型值为null/empty,则返回空字符串很重要,并且使用请选择" f:selectItem在p:selectOneMenu 中具有空值/空值.

getAsObject()

您需要实现

换句话说,从技术上讲,您必须能够将返回的对象作为getAsString()modelValue自变量传回,然后在无限循环中将获得的字符串作为getAsObject()submittedValue自变量传回.

用法

最后,只需使用 Converter > 挂接到有问题的对象类型上,然后当图片中出现Warehouse类型时,JSF将自动处理转换:

@FacesConverter(forClass=Warehouse.class)

这是规范的" JSF方法.毕竟它不是很有效,因为它确实确实也可以从<f:selectItems>中获取该项目.但是Converter的最重要一点是它返回一个 unique String表示形式,因此可以通过一个简单的String标识Java对象,该对象适合在HTTP和HTML中传递.

基于toString()的通用转换器

JSF实用程序库 OmniFaces 具有展示柜.

要使用它,只需将其注册如下:

<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">

并确保您的Warehouse实体的toString()返回该实体的唯一表示形式.例如,您可以直接返回ID:

@Override
public String toString() {
    return String.valueOf(id);
}

或更具有可读性/重用性的东西:

@Override
public String toString() {
    return "Warehouse[id=" + id + "]";
}

另请参见:


无关,由于JSF 2.0,不再明确要求将List<SelectItem>作为<f:selectItem>值.只需List<Warehouse>就足够了.

<h:selectOneMenu value="#{bean.selectedWarehouse}">
    <f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
    <f:selectItems value="#{bean.availableWarehouses}" var="warehouse"
        itemLabel="#{warehouse.name}" itemValue="#{warehouse}" />
</h:selectOneMenu>

private Warehouse selectedWarehouse;
private List<Warehouse> availableWarehouses;

I have problems understanding how to use selection in JSF 2 with POJO/entity effectively. For example, I'm trying to select a Warehouse entity via the below dropdown:

<h:selectOneMenu value="#{bean.selectedWarehouse}">
    <f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
    <f:selectItems value="#{bean.availableWarehouses}" />
</h:selectOneMenu>

And the below managed bean:

@Named
@ViewScoped
public class Bean {

    private Warehouse selectedWarehouse;
    private List<SelectItem> availableWarehouses;

    // ...

    @PostConstruct
    public void init() {
        // ...

        availableWarehouses = new ArrayList<>();

        for (Warehouse warehouse : warehouseService.listAll()) {
            availableWarehouses.add(new SelectItem(warehouse, warehouse.getName()));
        }
    }

    // ...
}

Notice that I use the whole Warehouse entity as the value of SelectItem.

When I submit the form, this fails with the following faces message:

Conversion Error setting value 'com.example.Warehouse@cafebabe' for 'null Converter'.

I was hoping that JSF could just set the correct Warehouse object to my managed bean when I wrap it in a SelectItem. Wrapping my entity inside the SelectItem was meant to skip creating a Converter for my entity.

Do I really have to use a Converter whenever I want to make use of entities in my <h:selectOneMenu>? It should for JSF be possible to just extract the selected item from the list of available items. If I really have to use a converter, what is the practical way of doing it? So far I came up to this:

  1. Create a Converter implementation for the entity.
  2. Overriding the getAsString(). I think I don't need this since the label property of the SelectItem will be used to display the dropdown option label.
  3. Overriding the getAsObject(). I think this will be used to return the correct SelectItem or entity depending on the type of the selected field defined in the managed bean.

The getAsObject() confuses me. What is the efficient way to do this? Having the string value, how do I get the associated entity object? Should I query the entity object from the service object based on the string value and return the entity? Or perhaps somehow I can access the list of the entities that form the selection items, loop them to find the correct entity, and return the entity?

What is the normal approach of this?

解决方案

Introduction

JSF generates HTML. HTML is in Java terms basically one large String. To represent Java objects in HTML, they have to be converted to String. Also, when a HTML form is submitted, the submitted values are treated as String in the HTTP request parameters. Under the covers, JSF extracts them from the HttpServletRequest#getParameter() which returns String.

To convert between a non-standard Java object (i.e. not a String, Number or Boolean for which EL has builtin conversions, or Date for which JSF provides builtin <f:convertDateTime> tag), you really have to supply a custom Converter. The SelectItem has no special purpose at all. It's just a leftover from JSF 1.x when it wasn't possible to supply e.g. List<Warehouse> directly to <f:selectItems>. It has also no special treatment as to labels and conversion.

getAsString()

You need to implement getAsString() method in such way that the desired Java object is been represented in an unique String representation which can be used as HTTP request parameter. Normally, the technical ID (the database primary key) is used here.

public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
    if (modelValue == null) {
        return "";
    }

    if (modelValue instanceof Warehouse) {
        return String.valueOf(((Warehouse) modelValue).getId());
    } else {
        throw new ConverterException(new FacesMessage(modelValue + " is not a valid Warehouse"));
    }
}

Note that returning an empty string in case of a null/empty model value is significant and required by the javadoc. See also Using a "Please select" f:selectItem with null/empty value inside a p:selectOneMenu.

getAsObject()

You need to implement getAsObject() in such way that exactly that String representation as returned by getAsString() can be converted back to exactly the same Java object specified as modelValue in getAsString().

public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
    if (submittedValue == null || submittedValue.isEmpty()) {
        return null;
    }

    try {
        return warehouseService.find(Long.valueOf(submittedValue));
    } catch (NumberFormatException e) {
        throw new ConverterException(new FacesMessage(submittedValue + " is not a valid Warehouse ID"), e);
    }
}

In other words, you must be technically able to pass back the returned object as modelValue argument of getAsString() and then pass back the obtained string as submittedValue argument of getAsObject() in an infinite loop.

Usage

Finally just annotate the Converter with @FacesConverter to hook on the object type in question, JSF will then automatically take care of conversion when Warehouse type ever comes into the picture:

@FacesConverter(forClass=Warehouse.class)

That was the "canonical" JSF approach. It's after all not very effective as it could indeed also just have grabbed the item from the <f:selectItems>. But the most important point of a Converter is that it returns an unique String representation, so that the Java object could be identified by a simple String suitable for passing around in HTTP and HTML.

Generic converter based on toString()

JSF utility library OmniFaces has a SelectItemsConverter which works based on toString() outcome of the entity. This way you do not need to fiddle with getAsObject() and expensive business/database operations anymore. For some concrete use examples, see also the showcase.

To use it, just register it as below:

<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">

And make sure that the toString() of your Warehouse entity returns an unique representation of the entity. You could for instance directly return the ID:

@Override
public String toString() {
    return String.valueOf(id);
}

Or something more readable/reusable:

@Override
public String toString() {
    return "Warehouse[id=" + id + "]";
}

See also:


Unrelated to the problem, since JSF 2.0 it's not explicitly required anymore to have a List<SelectItem> as <f:selectItem> value. Just a List<Warehouse> would also suffice.

<h:selectOneMenu value="#{bean.selectedWarehouse}">
    <f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
    <f:selectItems value="#{bean.availableWarehouses}" var="warehouse"
        itemLabel="#{warehouse.name}" itemValue="#{warehouse}" />
</h:selectOneMenu>

private Warehouse selectedWarehouse;
private List<Warehouse> availableWarehouses;

这篇关于“空转换器"的转换错误设置值-为什么在JSF中需要一个转换器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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