Validation Error: Value is not valid with CDI

49 views Asked by At

This is not a duplicate, but related to thread. Please not, the difference is the use of CDI instead of the traditional ManagedBean concept.

I have a category list producer ...

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;

import ch.winterraeder.model.Category;

@SessionScoped
public class CategoryListProducer implements Serializable {

    private static final long serialVersionUID = 8872019830611018574L;

    @Inject
    private CategoryRepository categoryRepository;

    private List<Category> categories;

    // @Named provides access the return value via the EL variable name
    // "categories" in the UI (e.g.
    // Facelets or JSP view)
    @Produces
    @ApplicationScoped
    @Named(value="categories")
    public List<Category> getCategories() {
        return categories;
    }

    public void onCategoryListChanged(
            @Observes(notifyObserver = Reception.IF_EXISTS) final Category category) {
        retrieveAllCategorysOrderedByName();
    }

    @PostConstruct
    public void retrieveAllCategorysOrderedByName() {
        categories = categoryRepository.findAllOrderedByName();
    }
}

... which delivers the categories for my ...

            <h:selectManyListbox id="parentCategories" value="#{newCategory.parentCategories}">
                <f:selectItems value="#{categories}" var="c" itemLabel="#{c.categoryName}" itemValue="#{c}"/>
                    <!-- CategoryConverter is Applied here -->
                    <f:converter converterId="categoryConverter" />
            </h:selectManyListbox >

When I press the add button ...

            <h:commandButton id="add" action="#{categoryController.add}"
                    value="Hinzufügen" styleClass="addButton" />

... I can successfully persist a new category but it fails if I select a parent category whith the CategoryController class.

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

import ch.winterraeder.data.CategoryRepository;
import ch.winterraeder.model.Category;

@Named
@SessionScoped
public class CategoryController implements Serializable {

    private static final long serialVersionUID = -6377428573950716575L;

    @Inject
    private FacesContext facesContext;

    @Inject
    private CategoryRepository categoryRepository;

    @Produces
    @Named
    private Category newCategory;

    @PostConstruct
    public void initNewMember() {
        newCategory = new Category();
    }

    public void add() throws Exception {
        try {
            categoryRepository.register(newCategory);
            FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_INFO,
                    "Registered!", "Registration successful");
            facesContext.addMessage(null, m);
            initNewMember();
        } catch (Exception e) {
            String errorMessage = e.getMessage();
            FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                    errorMessage, "Registration unsuccessful");
            facesContext.addMessage(null, m);
        }
    }
}

The error message is Validation Error: value is not valid. It's interesting, I can do the exact thing with @ManagedBean, but I fail to do it with the CDI.

I must be related to the initially linked threat and the select list is different when submitting the values. What am I missing?

Here is the model class to get an understanding of the data.

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.xml.bind.annotation.XmlRootElement;

import org.hibernate.validator.constraints.NotBlank;

@Entity
@XmlRootElement
public class Category {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @NotBlank
    private String categoryName;

    private boolean active = true;

    @ManyToMany(fetch=FetchType.LAZY, cascade={CascadeType.DETACH, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.PERSIST})
    private List<Category> parentCategories = new LinkedList<Category>();   

    @ManyToMany(mappedBy="parentCategories")
    private List<Category> childCategories = new LinkedList<Category>();

    private String imagePath;

    @SuppressWarnings("unused")
    private Date dateCreated;
    @SuppressWarnings("unused")
    private Date dateModified;

    /***** EVENT HOOKS *****/

    @PrePersist
    protected void onCreate() {
        dateCreated = new Date();
    }

    @PreUpdate
    protected void onUpdate() {
        dateModified = new Date();
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String category) {
        this.categoryName = category;
    }

    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    public List<Category> getParentCategories() {
        return parentCategories;
    }

    public void setParentCategories(List<Category> parentCategories) {
        this.parentCategories = parentCategories;
    }

    public List<Category> getChildCategories() {
        return childCategories;
    }

    public void setChildCategories(List<Category> childCategories) {
        this.childCategories = childCategories;
    }

    public String getImagePath() {
        return imagePath;
    }

    public void setImagePath(String imagePath) {
        this.imagePath = imagePath;
    }

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (active ? 1231 : 1237);
    result = prime * result
            + ((categoryName == null) ? 0 : categoryName.hashCode());
    result = prime * result
            + ((childCategories == null) ? 0 : childCategories.hashCode());
    result = prime * result
            + ((dateCreated == null) ? 0 : dateCreated.hashCode());
    result = prime * result
            + ((dateModified == null) ? 0 : dateModified.hashCode());
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    result = prime * result
            + ((imagePath == null) ? 0 : imagePath.hashCode());
    result = prime
            * result
            + ((parentCategories == null) ? 0 : parentCategories.hashCode());
    return result;
}

 @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Category other = (Category) obj;
        if (active != other.active)
            return false;
        if (categoryName == null) {
            if (other.categoryName != null)
                return false;
        } else if (!categoryName.equals(other.categoryName))
            return false;
        if (childCategories == null) {
            if (other.childCategories != null)
                return false;
        } else if (!childCategories.equals(other.childCategories))
            return false;
        if (dateCreated == null) {
            if (other.dateCreated != null)
                return false;
        } else if (!dateCreated.equals(other.dateCreated))
            return false;
        if (dateModified == null) {
            if (other.dateModified != null)
                return false;
        } else if (!dateModified.equals(other.dateModified))
            return false;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        if (imagePath == null) {
            if (other.imagePath != null)
                return false;
        } else if (!imagePath.equals(other.imagePath))
            return false;
        if (parentCategories == null) {
            if (other.parentCategories != null)
                return false;
        } else if (!parentCategories.equals(other.parentCategories))
            return false;
        return true;
    }

    }

Here is my converter ...

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
import javax.inject.Inject;

import ch.winterraeder.data.CategoryRepository;
import ch.winterraeder.model.Category;

@FacesConverter(forClass=Category.class, value="categoryConverter")
public class CategoryConverter implements Converter {

    @Inject
    CategoryRepository catRepo;

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

        if (value.isEmpty()) {
            return null;
        }
        Long id = new Long(value);        
        try{
            Category cat = catRepo.findById(id);
            return cat;
        }catch (Exception ex){
            throw new ConverterException(new FacesMessage("Category cannot be fetched with value " + value));
        }

    }

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

        if (value == null || value.toString().isEmpty()) {
            return "";
        }
        Category cat = (Category) value;
        return cat.getId().toString();
    }
}
0

There are 0 answers