私はJSFを初めて使用し、h:selectOneMenuを使用して製品のカテゴリを取得するフォームからデータを保存しようとしています。 h:selectOneMenuがDBから入力されていますが、製品をDBに保存しようとすると、エラーが発生します。「nullConverter」の変換エラー設定値「52」。 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());
}
}
コードは元の問題から更新され、コードは完全に機能するようになりました。
JSF Converter を作成せずに、<h:selectOneMenu/>
コンポーネント(または<h:selectXXXX/>
のいずれか)でカスタムタイプを使用することはできません。コンバーターはJSFに存在し、基本的にカスタムまたはサーバー側のアイテム/構成をWebページに適した/人間が読める形式に変換し、クライアント側からサーバー側に選択内容を保存できるようにします。したがって、エラーメッセージが本質的に示しているのは、クライアント側から送信された値52
を、サーバー側にCategory
オブジェクト/タイプとして保存するのに十分な意味がないということです。
したがって、実行する必要があるのは、JSFがconverter
オブジェクトを理解するのに本質的に役立つJSFCategory
の実装を作成することです。
これがあなたがする必要があることの大まかな見積もりです:
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();
}
}
<h:selectOneMenu/>
で新しいコンバーターを参照します
<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
という名前を使用しています。それ以外の場合は、コンバーターアノテーションに設定した名前を使用します。
Product.category_fkはタイプCategoryのようで、prodCat.category_idはIntegerか何かであると思われます...
xhtmlで、selectItemsの値を次のように設定しているようです。itemValue="#{prodCat.category_id}"
selectOneMenuが値を期待する場合value="#{productController.product.category_fk}"
おそらく同じタイプではありません。