Conversion Error setting value '52' for 'null Converter' [duplicate]
Asked Answered
M

2

8

I'm new to JSF and I have been trying to store data from a form that uses a h:selectOneMenu to get the category of a product. The h:selectOneMenu is being populated from the DB, however, when trying to store a product in the DB, I am getting an error: Conversion Error setting value '52' for 'null Converter'. I have reviewed similar problems in StackOverflow and tutorials online but I am still getting the error.

This is the 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>

This is the product controller:

@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

This is the EJB simplified for simplicity:

   @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;
        }    

    }

This is the product Entity simplified for simplicity:

@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;

This is the updated converter I am using:

@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());

    }

}

The code has been updated from the Orignal problem, the code perfectly works now.

Mayfield answered 1/11, 2012 at 17:43 Comment(0)
K
11

You can't use a custom type on the <h:selectOneMenu/> component (or any of the <h:selectXXXX/>) without creating a JSF Converter. Converters exist in JSF to assist with translating essentially custom or sever-side items/constructs into web page friendly/human readable formats and also to be able to save selections from the client side back to the server side. So what the error message is essentially telling you there is that it cannot make sense enough of the value 52 submitted from the client side to save it to the server side as a Category object/type

So what you're required to do is to create an implementation of a JSF converter that essentially helps JSF make sense of your Category object.

Here's a rough estimation of what you need to do:

  1. Implement a converter for your Category type:

    // 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. Reference your new converter in your <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>
    

We're using the name categoryConverterBean because we want to take advantage of the entity manager trick you pulled in the converter. Any other case, you would've used the name you set on the converter annotation.

Kantar answered 2/11, 2012 at 4:28 Comment(8)
Thank you very much. I have been reading about Converters since yesterday, but I wasn't able to really understand it until your explanation. I tried implementing your suggestions, however, I'm getting a new error now, a java.lang.ExceptionInInitializerError 'Caused by: java.lang.RuntimeException: Uncompilable source code - class CategoryConverterimplements is public, should be declared in a file named CategoryConverterimplements.java at com.lv.Controllers.Converters.CategoryConverterimplements.<clinit>(CategoryConverter.java:17)'Mayfield
I have also updated the posting with the code that I added with the converter, as well as the xhtml portion of the listing. Please let me know if you have any ideas how to solve this bug. Thanks in advance. java.lang.ExceptionInInitializerError 'Caused by: java.lang.RuntimeException: Uncompilable source code - class CategoryConverterimplements is public, should be declared in a file named CategoryConverterimplements.java at com.lv.Controllers.Converters.CategoryConverterimplements.<clinit>(CategoryConve‌​rter.java:17)'Mayfield
@Mayfield the problem is not really with your source, looks more like your file naming for your sources is wrong: the converter is implemented as a class called CategoryConverter so the .java file should be called CategoryConverter.java. Is this what you have? Because, from the exception, it looks like your class is named CategoryConverterimplements instead. Also, I see you're returning a getName() in your getAsString implementation. This won't work. Whatever you're returning in your getAsString is what will be supplied as Value to your getAsObject implementation.Kantar
@Mayfield what you return in your getAsString implementation should be what you can use in your getAsObject to search for the object. For this, I advise a unique id type valueKantar
thanks again. I chose to leave @ManagedBean without name specified name and the error stop showing. However, for the getAsString I'm trying to return something like this: return ((Category)value).getCategory_id().toString(); but I keep on getting int cannot be dereferenced so it wouldn't even run. I have updated the code reflecting the last changes. Thanks in advance.Mayfield
@lv10, that exception indicates you're trying to call an illegal operation on an int type. What type does getCategory_id() return? If it's an int, i suggest you just use String.valueOf(getCategory_id()) there insteadKantar
thanks you very much again. I have finally solved the problem. I did it by changing the f:selectedItems to <f:selectItems value="#{productController.categoryList}" var="prodCat" itemValue="#{prodCat}" itemLabel="#{prodCat.name}"/> and using Category category; category = (Category) value; return String.valueOf(category.getCategory_id()); in the getAsString method.Mayfield
@Kantar I thought, once could insert @PersistenceContext(unitName = "luavipuPU") only in EJBs not in managed beans (could you in CDI-beans)?Detestation
M
2

Product.category_fk seems to be of type Category and I suspect prodCat.category_id to be an Integer or something...

in your xhtml you seem to set the value of the selectItems to: itemValue="#{prodCat.category_id}"

when selectOneMenu expects a value value="#{productController.product.category_fk}"

which are most probably not of the same type.

Mciver answered 1/11, 2012 at 18:10 Comment(3)
I made the change, however I am no getting another error. I'm getting this: Conversion Error setting value 'Category{category_id=52, name=Libros - Conflicto Armado, description=lualvipu, product_fk={IndirectList: not instantiated}}' for 'null Converter'.Mayfield
So I am not completely sure if this is still related to the previous problem. Thank you very muchMayfield
I am not sure to understand your error message, but you can always try to wrap your objects in a list of javax.faces.model.SelectItem... it might help you understand what a selectOneMenu needs to workMciver

© 2022 - 2024 — McMap. All rights reserved.