转换错误:为“null转换器”设置值“52”。

8

我是JSF的新手,一直在尝试存储使用h:selectOneMenu获取产品类别的表单数据。 h:selectOneMenu从数据库中获取,但是当尝试将产品存储到数据库中时,我收到错误提示:Conversion Error setting value '52' for 'null Converter'。我已经在StackOverflow和在线教程中查看了类似的问题,但我仍然遇到了错误。

这是xhtml代码:

<h:selectOneMenu id="category_fk" value="#{productController.product.category_fk}" 
                                 converter="#{categoryConverter}" title="Category_fk" >
                    <!-- DONE: update below reference to list of available items-->
                    <f:selectItems value="#{productController.categoryList}" var="prodCat"
                                   itemValue="#{prodCat}" itemLabel="#{prodCat.name}"/>
                </h:selectOneMenu>

这是产品控制器:
@Named
@RequestScoped
public class ProductController {

    @EJB
    private ProductEJB productEjb;
    @EJB
    private CategoryEJB categoryEjb;

    private Product product = new Product();
    private List<Product> productList = new ArrayList<Product>();

    private Category category;
    private List<Category> categoryList = new ArrayList<Category>();

    public String doCreateProduct()
    {
        product = productEjb.createProduct(product);
        productList = productEjb.findAllProducts();
        return "listProduct";
    }

    @PostConstruct
    public void init()
    {
        categoryList = categoryEjb.findAllCategory();
        productList = productEjb.findAllProducts();
    }        

    // Getters/Setters and other methods omitted for simplicity

这是为简化而简化的EJB:

   @Stateless
    public class ProductEJB{

        @PersistenceContext(unitName = "luavipuPU")
        private EntityManager em;

        public List<Product> findAllProducts()
        {
            TypedQuery<Product> query = em.createNamedQuery("findAllProducts", Product.class);
            return query.getResultList();
        }

        public Product createProduct(Product product)
        {
            em.persist(product);
            return product;
        }    

    }

这是简化后的产品实体:

@Entity
@NamedQueries({
    @NamedQuery(name="findAllProducts", query = "SELECT p from Product p")
})
public class Product implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id @GeneratedValue(strategy= GenerationType.AUTO)
    private int product_id;
    private String name;
    private String description;
    protected byte[] imageFile;
    private Float price;
    @Temporal(TemporalType.TIMESTAMP)
    private Date dateAdded;
    @ManyToOne    
    private Category category_fk;
    @ManyToOne
    private SaleDetails saleDetails_fk;

这是我正在使用的更新转换器:

@ManagedBean
@FacesConverter(value="categoryConverter")
public class CategoryConverter implements Converter{

    @PersistenceContext
    private transient EntityManager em;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        return em.find(Category.class, new Integer(value));
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {

        Category category;
        category = (Category) value;
        return String.valueOf(category.getCategory_id());

    }

}

代码已经从原始问题中进行了更新,现在代码完美运行。

2个回答

11

如果您想在<h:selectOneMenu/>组件(或任何一个<h:selectXXXX/>)中使用自定义类型,则需要创建JSF Converter。在JSF中,转换器用于帮助将自定义或服务器端项目/结构翻译为网页友好/易读的格式,并能够将客户端的选择保存回服务器端。因此,错误消息基本上告诉您,它无法对从客户端提交的值52 进行足够的解释来将其保存到服务器端作为Category对象/类型。

因此,您需要创建JSF converter的实现,以帮助JSF理解您的Category对象。

以下是大致需要执行的操作:

  1. Category类型实现转换器:

    // You must annotate the converter as a managed bean, if you want to inject
    // anything into it, like your persistence unit for example.
    @ManagedBean(name = "categoryConverterBean") 
    @FacesConverter(value = "categoryConverter")
    public class CategoryConverter implements Converter {
    
        @PersistenceContext(unitName = "luavipuPU")
        // I include this because you will need to 
        // lookup  your entities based on submitted values
        private transient EntityManager em;  
    
        @Override
        public Object getAsObject(FacesContext ctx, UIComponent component,
                String value) {
          // This will return the actual object representation
          // of your Category using the value (in your case 52) 
          // returned from the client side
          return em.find(Category.class, new BigInteger(value)); 
        }
    
        @Override
        public String getAsString(FacesContext fc, UIComponent uic, Object o) {
            //This will return view-friendly output for the dropdown menu
            return ((Category) o).getId().toString(); 
        }
    }
    
  2. 在您的<h:selectOneMenu/>中引用您的新转换器

  3. <h:selectOneMenu id="category_fk" 
      converter="#{categoryConverterBean}"
      value="#productController.product.category_fk}" 
      title="Category_fk" >
    <!-- DONE: update below reference to list of available items-->
        <f:selectItems value="#{productController.categoryList}" 
          var="prodCat" itemValue="#{prodCat.category_id}" 
          itemLabel="#{prodCat.name}"/>
    </h:selectOneMenu>
    

我们使用名称categoryConverterBean,因为我们想利用你在转换器中使用的实体管理器技巧。在任何其他情况下,您都将使用转换器注释上设置的名称。


@lv10 问题并不在于您的源代码上,看起来更像是您的文件命名有误:转换器作为名为 CategoryConverter 的类实现,因此 .java 文件应该被命名为 CategoryConverter.java。您这么做了吗?因为从异常信息看来,你的类名却是 CategoryConverterimplements。此外,我发现您在 getAsString 实现中返回了 getName()。这是行不通的。无论您在 getAsString 中返回什么,都将作为 getAsObject 实现的 Value 提供。 - kolossus
@lv10 在你的 getAsString 实现中返回的内容应该是你在 getAsObject 中用于搜索对象的内容。为此,我建议使用唯一的 id 类型值。 - kolossus
再次感谢。我选择不指定名称离开@ManagedBean,错误停止显示。然而,在getAsString中,我正在尝试返回类似于此的内容:return ((Category)value).getCategory_id().toString();但我一直收到int cannot be dereferenced的错误,因此它甚至无法运行。我已更新代码以反映最新更改。提前致谢。 - lv10
@lv10,该异常指示您试图在“int”类型上调用非法操作。 getCategory_id()返回什么类型? 如果是int,则建议您在那里使用String.valueOf(getCategory_id()) - kolossus
@kolossus 我认为,@PersistenceContext(unitName = "luavipuPU")只能在EJB中插入,而不能在托管的Bean中插入(您能在CDI Bean中插入吗?) - feder
显示剩余3条评论

2

Product.category_fk似乎是Category类型,我猜测prodCat.category_id是整数或其他类型...

在你的xhtml中,你似乎将selectItems的值设置为:itemValue="#{prodCat.category_id}"

而selectOneMenu期望一个值为value="#{productController.product.category_fk}"

这两个值很可能不是相同的类型。


我进行了更改,但是我又遇到了另一个错误。我得到了这个: 在“null转换器”中设置值“Category {category_id = 52,name = Libros-Conflicto Armado,description = lualvipu,product_fk = {IndirectList:not instantiated}}”时出现转换错误。 - lv10
所以我不完全确定这是否仍然与先前的问题有关。非常感谢。 - lv10
我不确定是否理解您的错误消息,但您可以尝试将对象包装在javax.faces.model.SelectItem列表中...这可能有助于您了解selectOneMenu需要什么。 - ChaudPain

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