0

I m working on a project with jsf spring hibernate and primefaces. I have a form in which I add items. One field of that form is not a primitive type but an custom object. I know I have to use a converter and get the object I choose. I have tryied a custom converter with no luck since I cant inject the service and is always null. So I turned to omnifaces to make my life easier and move on. Unfortunately I have problems with that too. I look over and over my code but I cant see whats wrong. Below I add the code related to the problem: First the page I use omnifaces:

<html xmlns="http://www.w3.org/1999/xhtml"  
 xmlns:h="http://java.sun.com/jsf/html"      
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:p="http://primefaces.org/ui"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:o="http://omnifaces.org/ui"
    xmlns:of="http://omnifaces.org/functions">
<h:head><title>Welcome to OTV_JSF_Spring_Hibernate_Project</title></h:head>  
<h:body>
    <ui:include src="/pages/topMenu.xhtml"/>
    <h:form>
        <table>
            <tr>
                <td><h:outputLabel for="itemId" value="id: "/></td>
                <td><h:inputText id="itemId" value="#{inventoryItemsMB.itemId}"></h:inputText></td>
            </tr>


            <tr>
                <td><h:outputLabel for="RefItemCategories" value="Category Code"/></td>
                <td>
                    <h:selectOneMenu value="#{inventoryItemsMB.refItemCategories}" id="refItemCategories" immediate="true" converter="omnifaces.SelectItemsConverter">

                        <f:selectItems  value="#{refItemCategoriesMB.refItemCategoriesList}" var="ref" itemLabel="#{ref.itemCategoryDescription}" itemValue="#{ref}"/>
                        <!--<f:converter converterId="catConverter"/>-->
                    </h:selectOneMenu>
                </td>
            </tr>

            <tr>
                <td><h:outputLabel for="description" value="Description"/></td>
                <td><h:inputText id="description" value="#{inventoryItemsMB.description}" immediate="false"></h:inputText></td>
            </tr>

            <tr>
                <td><h:outputLabel for="AvgMonthlyUsage" value="Average Monthly Usage: "/></td>
                <td><h:inputText id="AvgMonthlyUsage" value="#{inventoryItemsMB.avgMonthlyUsage}"></h:inputText></td>
            </tr>
            <tr>
                <td><h:outputLabel for="reorderQuantity" value="Reorder Quantity: "/></td>
                <td><h:inputText id="reorderQuantity" value="#{inventoryItemsMB.reorderQuantity}"></h:inputText></td>
            </tr>
            <tr>
                <td><h:outputLabel for="Price" value="Price: "/></td>
                <td><h:inputText id="Price" value="#{inventoryItemsMB.price}"></h:inputText></td>
            </tr>
            <tr>
                <td><h:outputLabel for="ItemStockLevels" value="Item stock levels: "/></td>
                <td><h:inputText id="ItemStockLevels" value="#{itemStockLevelsMB.quantityInStock}"></h:inputText></td>
            </tr>
            <tr>
                <td><p:commandButton id="addInventoryItems" value="ADD" action="#{inventoryItemsMB.addInventoryItems}" ajax="false" immediate="false"/></td>
            </tr>
        </table>
    </h:form>

</h:body>

Secondly my managedBeans:

@ManagedBean(name="inventoryItemsMB")
   @RequestScoped
   public class InventoryItemsManagedBean implements Serializable {

private static final long serialVersionUID = 1L;
private static final String SUCCESS = "successInventoryItems";
private static final String ERROR   = "error";

@ManagedProperty(value="#{InventoryItemsService}")
IInventoryItemsService inventoryItemsService;

List<InventoryItems> inventoryItemsList;

private int id;
private String avgMonthlyUsage;
String description;
Set<ItemStockLevels> itemStockLevels;
float price;
String reorderQuantity;
RefItemCategories refItemCategories;
byte[] photo;

public String addInventoryItems(){
    try{
        InventoryItems inventoryItems = new InventoryItems();
        //RefItemCategories refItemCategories = new RefItemCategories();
        inventoryItems.setAvgMonthlyUsage(getAvgMonthlyUsage());//DONE is it a string?look at impl
        inventoryItems.setDescription(getDescription());//DONE
        inventoryItems.setItemId(getItemId());//DONE
        inventoryItems.setItemStockLevels(getItemStockLevels());//DONE ----- why is it a set?
        inventoryItems.setPhoto(getPhoto());
        inventoryItems.setPrice(getPrice());//DONE
        inventoryItems.setRefItemCategories(getRefItemCategories());//DONE---why refItemCategories
        inventoryItems.setReorderQuantity(getReorderQuantity());//DONE-----why string?
        //refItemCategories.getItemCategoryCode();
        //refItemCategories.getItemCategoryDescription();
        getInventoryItemsService().addInventoryItems(refItemCategories, inventoryItems);
        return SUCCESS;
    } catch (DataAccessException e) {
        e.printStackTrace();
    }
    return ERROR;
}

public List<InventoryItems> getInventoryItemsList() {
    inventoryItemsList = new ArrayList<InventoryItems>();
    inventoryItemsList.addAll(getInventoryItemsService().getInventoryItems());
    return inventoryItemsList;
}

public IInventoryItemsService getInventoryItemsService() {
return inventoryItemsService;
}


public void setInventoryItemsService(IInventoryItemsService inventoryItemsService) {
this.inventoryItemsService = inventoryItemsService;
}

public void setInventoryItemsList(List<InventoryItems> inventoryItemsList) {
this.inventoryItemsList = inventoryItemsList;
}

public int getItemId() {
    return id;
}

public void setItemId(int id) {
    this.id = id;
}

public void setAvgMonthlyUsage(String avgMonthlyUsage){
    this.avgMonthlyUsage = avgMonthlyUsage;
}

public String getAvgMonthlyUsage(){
    return avgMonthlyUsage;
}

public void setDescription(String description){
    this.description = description;
}

public String getDescription(){
    return description;
}

public void setItemStockLevelses(Set<ItemStockLevels> itemStockLevels){
    this.itemStockLevels = itemStockLevels;
}

public Set<ItemStockLevels> getItemStockLevels(){
    return itemStockLevels;
}

public void setPrice(float price){
    this.price = price;
}

public float getPrice(){
    return price;
}

public void setReorderQuantity(String reorderQuantity){
    this.reorderQuantity = reorderQuantity;
}

public String getReorderQuantity(){
    return reorderQuantity;
}

public void setRefItemCategories(RefItemCategories refItemCategories){
    this.refItemCategories = refItemCategories;
}

public RefItemCategories getRefItemCategories(){
    return refItemCategories;
}

public byte[] getPhoto(){
    return photo;
}

public void setPhoto(byte[] photo){
    this.photo = photo;
}

}

and the other managedbean

 @ManagedBean(name="refItemCategoriesMB")
@RequestScoped
public class RefItemCategoriesManagedBean implements Serializable{
    private static final long serialVersionUID = 1L;
    private static final String SUCCESS = "addCategorySuccess";
    private static final String ERROR   = "error";

@ManagedProperty(value="#{RefItemCategoriesService}")
IRefItemCategoriesService refItemCategoriesService;

List<RefItemCategories> refItemCategoriesList;

private int id;
private String description;

public String addRefItemCategories(){
    try{
        RefItemCategories refItemCategories = new RefItemCategories();
        refItemCategories.setItemCategoryCode(getItemCategoryCode());
        refItemCategories.setItemCategoryDescription(getItemCategoryDescription());
        getRefItemCategoriesService().addRefItemCategories(refItemCategories);
        return SUCCESS;
    } catch (DataAccessException e){
        e.printStackTrace();
    }
    return ERROR;
}

public List<RefItemCategories> getRefItemCategoriesList() {
    refItemCategoriesList = new ArrayList<RefItemCategories>();
    refItemCategoriesList.addAll(getRefItemCategoriesService().getRefItemCategories());
    return refItemCategoriesList;
}

public IRefItemCategoriesService getRefItemCategoriesService() {
return refItemCategoriesService;
}

public void setRefItemCategoriesService(IRefItemCategoriesService refItemCategoriesService) {
this.refItemCategoriesService = refItemCategoriesService;
}

public void setRefItemCategoriesList(List<RefItemCategories> refItemCategoriesList) {
this.refItemCategoriesList = refItemCategoriesList;
}

public String DeleteCategory(RefItemCategories refItemCategoriesList){
    getRefItemCategoriesService().deleteRefItemCategories(refItemCategoriesList);
    return SUCCESS;
}


public void setItemCategoryCode(int id){
    this.id = id;
}

public int getItemCategoryCode(){
    return id;
}

public void setItemCategoryDescription(String description){
    this.description = description;
}

public String getItemCategoryDescription(){
    return description;
}

 @Override
public boolean equals(Object object){
if(this.id == ((RefItemCategories) object).getItemCategoryCode()) {
    return true;
}else {
    return false;
}

}

}

the service Im not able to inject:

 @Transactional(readOnly = true)
@Service("RefItemCategoriesService")
public class RefItemCategoriesService implements IRefItemCategoriesService{

    @Autowired
    RefItemCategoriesDAOImpl refItemCategoriesDAO;

    @Transactional(readOnly = false)
    @Override
    public void addRefItemCategories(RefItemCategories refItemCategories) {
        getRefItemCategoriesDAO().addRefItemCategories(refItemCategories);
    }

    @Transactional(readOnly = false)
    @Override
    public void updateRefItemCategories(RefItemCategories refItemCategories) {
        getRefItemCategoriesDAO().updateRefItemCategoriesUser(refItemCategories);
    }

    @Transactional(readOnly = false)
    @Override
    public void deleteRefItemCategories(RefItemCategories refItemCategories) {
        getRefItemCategoriesDAO().deleteRefItemCategories(refItemCategories);
    }

    @Override
    public RefItemCategories getRefItemCategoriesByID(int id) {
        return getRefItemCategoriesDAO().getRefItemCategoriesById(id);
    }

    @Override
    public List<RefItemCategories> getRefItemCategories() {
        return getRefItemCategoriesDAO().getRefItemCategories();
    }

    public RefItemCategoriesDAO getRefItemCategoriesDAO(){
        return refItemCategoriesDAO;
    }
}

this way I get a transactional error where item_cat_code (the db table) cannot be null. Thank you for your time.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Copolla87
  • 13
  • 5
  • For code snippets in your future questions, please read http://stackoverflow.com/help/mcve. There is way too much noise in the code posted so far. Surely for example the HTML `` element, the `price` input field and `updateRefItemCategories()` method don't play a role in the problem. The problem would still manifest when you remove them. This is true for about 70% of this code. This is unhelpful in spotting the cause of the problem by just looking at the code. In the future, copypaste code to a new project and remove as many as possible lines as long as the problem still exhibits. Okay?
    – BalusC Aug 13 '14 at 17:21

1 Answers1

4

As per the documentation, the omnifaces.SelectItemsConverter relies on the Object#toString() representation of the to-be-converted object to properly match the selected item. You didn't show the code of your RefItemCategories entity, so it's just guessing, but the symptoms indicate that you indeed didn't @Override the toString() on your entity, and it is thus relying on the default FQN@hashcode representation. This all would then only work if the available items (the value of <f:selectItems>) is exactly the same across postbacks on the same view.

However, the RefItemCategoriesManagedBean backing bean which provides the available items is request scoped and loads them in a getter. Everytime the getter is hit, a brand new list with brand new instances is returned. Those don't have the same hashcode as those which are already loaded in the list of available items and the submitted selected item thus never matches any of the newly loaded items.

That are thus at least 2 design problems.

  1. You should choose the right bean scope for the data it holds. Make it at least @ViewScoped.
  2. You should never interact with the DB in a getter method. Do it in @PostConstruct.

If you fix both, then the problem should disappear.

Or, just implement the toString() for your entity. E.g.

public class RefItemCategories {

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

}

By the way, it's strange to see an equals() method on the RefItemCategoriesManagedBean backing bean class. Didn't you mean to put it on the RefItemCategories entity instead? In any way, carefully read the documentation of SelectItemsConverter how to properly use it and how to properly design your entities.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I am more than thankful for your answer and instructions. Not only I solved the problem but I aquired quite some knowledge. I solved the problem by implementing toString(), equals() in RefItemCategories and changed the scoped annotation to ViewScope to both beans. You were right too for the noise in my post, I ll take a further look to the link you provided.Thanks again. – Copolla87 Aug 13 '14 at 18:05