'How can we enable many to many relationship through a JSF page using Netbeans?

Used a simple InnoDB MySQL database (many to many relationship between WRITER and FORUM, and a join table named writer_forum) in Netbeans 7.1 and created a Java EE 6 web application running under Glassfish 3.1 Open Source Edition. No Other frameworks are being used except JSF 2.0

  • Generated Entities from Database (using EclipseLink (JPA 2.0) and everything seems fine, the code in the entities is correct as far as I can tell.
  • Generated JSF pages from Entities (the IDE generates EJB Session beans, Managed Beans and JSF pages using facelets .xhtml).

ALl relationships are supported except MANY TO MANY. Does anyone had the same experience and managed to enable Many to Many relationship support?

package entities;

@Entity
@Table(name = "writer")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Writer.findAll", query = "SELECT w FROM Writer w"),
    @NamedQuery(name = "Writer.findByWriterid", query = "SELECT w FROM Writer w WHERE w.writerid = :writerid"),
    @NamedQuery(name = "Writer.findByName", query = "SELECT w FROM Writer w WHERE w.name = :name"),
    @NamedQuery(name = "Writer.findBySurname", query = "SELECT w FROM Writer w WHERE w.surname = :surname"),
    @NamedQuery(name = "Writer.findByField", query = "SELECT w FROM Writer w WHERE w.field = :field")})
public class Writer implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @NotNull
    @Column(name = "writerid")
    private Integer writerid;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 45)
    @Column(name = "name")
    private String name;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 45)
    @Column(name = "surname")
    private String surname;
    @Size(max = 45)
    @Column(name = "field")
    private String field;
    @ManyToMany(mappedBy = "writerCollection")
    private Collection<Forum> forumCollection;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "writer")
    private Collection<Book> bookCollection;

    public Writer() {
    }

    public Writer(Integer writerid) {
        this.writerid = writerid;
    }

    public Writer(Integer writerid, String name, String surname) {
        this.writerid = writerid;
        this.name = name;
        this.surname = surname;
    }

    public Integer getWriterid() {
        return writerid;
    }

    public void setWriterid(Integer writerid) {
        this.writerid = writerid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    @XmlTransient
    public Collection<Forum> getForumCollection() {
        return forumCollection;
    }

    public void setForumCollection(Collection<Forum> forumCollection) {
        this.forumCollection = forumCollection;
    }

    @XmlTransient
    public Collection<Book> getBookCollection() {
        return bookCollection;
    }

    public void setBookCollection(Collection<Book> bookCollection) {
        this.bookCollection = bookCollection;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (writerid != null ? writerid.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Writer)) {
            return false;
        }
        Writer other = (Writer) object;
        if ((this.writerid == null && other.writerid != null) || (this.writerid != null && !this.writerid.equals(other.writerid))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return name + " | " + writerid;
    }

}

-------- FORUM JPA entity

 @Entity
    @Table(name = "forum")
    @XmlRootElement
    @NamedQueries({
        @NamedQuery(name = "Forum.findAll", query = "SELECT f FROM Forum f"),
        @NamedQuery(name = "Forum.findByForumid", query = "SELECT f FROM Forum f WHERE f.forumid = :forumid"),
        @NamedQuery(name = "Forum.findByLabel", query = "SELECT f FROM Forum f WHERE f.label = :label")})
    public class Forum implements Serializable {
        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Basic(optional = false)
        @NotNull
        @Column(name = "forumid")
        private Integer forumid;
        @Size(max = 45)
        @Column(name = "label")
        private String label;
        @JoinTable(name = "forum_writer", joinColumns = {
            @JoinColumn(name = "forum_forumid", referencedColumnName = "forumid")}, inverseJoinColumns = {
            @JoinColumn(name = "writer_writerid", referencedColumnName = "writerid")})
        @ManyToMany
        private Collection<Writer> writerCollection;

        public Forum() {
        }

        public Forum(Integer forumid) {
            this.forumid = forumid;
        }

        public Integer getForumid() {
            return forumid;
        }

        public void setForumid(Integer forumid) {
            this.forumid = forumid;
        }

        public String getLabel() {
            return label;
        }

        public void setLabel(String label) {
            this.label = label;
        }

        @XmlTransient
        public Collection<Writer> getWriterCollection() {
            return writerCollection;
        }

        public void setWriterCollection(Collection<Writer> writerCollection) {
            this.writerCollection = writerCollection;
        }

        @Override
        public int hashCode() {
            int hash = 0;
            hash += (forumid != null ? forumid.hashCode() : 0);
            return hash;
        }

        @Override
        public boolean equals(Object object) {
            // TODO: Warning - this method won't work in the case the id fields are not set
            if (!(object instanceof Forum)) {
                return false;
            }
            Forum other = (Forum) object;
            if ((this.forumid == null && other.forumid != null) || (this.forumid != null && !this.forumid.equals(other.forumid))) {
                return false;
            }
            return true;
        }

        @Override
        public String toString() {
            return "entities.Forum[ forumid=" + forumid + " ]";
        }

    }

Asbtract Facade

 public abstract class AbstractFacade<T> {
        private Class<T> entityClass;

        public AbstractFacade(Class<T> entityClass) {
            this.entityClass = entityClass;
        }

        protected abstract EntityManager getEntityManager();

        public void create(T entity) {
            getEntityManager().persist(entity);
        }

        public void edit(T entity) {
            getEntityManager().merge(entity);
        }

        public void remove(T entity) {
            getEntityManager().remove(getEntityManager().merge(entity));
        }

        public T find(Object id) {
            return getEntityManager().find(entityClass, id);
        }

        public List<T> findAll() {
            javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
            cq.select(cq.from(entityClass));
            return getEntityManager().createQuery(cq).getResultList();
        }

        public List<T> findRange(int[] range) {
            javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
            cq.select(cq.from(entityClass));
            javax.persistence.Query q = getEntityManager().createQuery(cq);
            q.setMaxResults(range[1] - range[0]);
            q.setFirstResult(range[0]);
            return q.getResultList();
        }

        public int count() {
            javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
            javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
            cq.select(getEntityManager().getCriteriaBuilder().count(rt));
            javax.persistence.Query q = getEntityManager().createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        }

    }

Forum Facade

@Stateless
public class ForumFacade extends AbstractFacade<Forum> {
    @PersistenceContext(unitName = "writerPU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public ForumFacade() {
        super(Forum.class);
    }

}

------------- Managed Bean

 @ManagedBean(name = "writerController")
    @SessionScoped
    public class WriterController implements Serializable {

        private Writer current;
        private DataModel items = null;
        @EJB
        private session.WriterFacade ejbFacade;
        private PaginationHelper pagination;
        private int selectedItemIndex;

        public WriterController() {
        }

        public Writer getSelected() {
            if (current == null) {
                current = new Writer();
                selectedItemIndex = -1;
            }
            return current;
        }

        private WriterFacade getFacade() {
            return ejbFacade;
        }

        public PaginationHelper getPagination() {
            if (pagination == null) {
                pagination = new PaginationHelper(10) {

                    @Override
                    public int getItemsCount() {
                        return getFacade().count();
                    }

                    @Override
                    public DataModel createPageDataModel() {
                        return new ListDataModel(getFacade().findRange(new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
                    }
                };
            }
            return pagination;
        }

        public String prepareList() {
            recreateModel();
            return "List";
        }

        public String prepareView() {
            current = (Writer) getItems().getRowData();
            selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
            return "View";
        }

        public String prepareCreate() {
            current = new Writer();
            selectedItemIndex = -1;
            return "Create";
        }

        public String create() {
            try {
                getFacade().create(current);
                JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("WriterCreated"));
                return prepareCreate();
            } catch (Exception e) {
                JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
                return null;
            }
        }

        public String prepareEdit() {
            current = (Writer) getItems().getRowData();
            selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
            return "Edit";
        }

        public String update() {
            try {
                getFacade().edit(current);
                JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("WriterUpdated"));
                return "View";
            } catch (Exception e) {
                JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
                return null;
            }
        }

        public String destroy() {
            current = (Writer) getItems().getRowData();
            selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
            performDestroy();
            recreatePagination();
            recreateModel();
            return "List";
        }

        public String destroyAndView() {
            performDestroy();
            recreateModel();
            updateCurrentItem();
            if (selectedItemIndex >= 0) {
                return "View";
            } else {
                // all items were removed - go back to list
                recreateModel();
                return "List";
            }
        }

        private void performDestroy() {
            try {
                getFacade().remove(current);
                JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("WriterDeleted"));
            } catch (Exception e) {
                JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            }
        }

        private void updateCurrentItem() {
            int count = getFacade().count();
            if (selectedItemIndex >= count) {
                // selected index cannot be bigger than number of items:
                selectedItemIndex = count - 1;
                // go to previous page if last page disappeared:
                if (pagination.getPageFirstItem() >= count) {
                    pagination.previousPage();
                }
            }
            if (selectedItemIndex >= 0) {
                current = getFacade().findRange(new int[]{selectedItemIndex, selectedItemIndex + 1}).get(0);
            }
        }

        public DataModel getItems() {
            if (items == null) {
                items = getPagination().createPageDataModel();
            }
            return items;
        }

        private void recreateModel() {
            items = null;
        }

        private void recreatePagination() {
            pagination = null;
        }

        public String next() {
            getPagination().nextPage();
            recreateModel();
            return "List";
        }

        public String previous() {
            getPagination().previousPage();
            recreateModel();
            return "List";
        }

        public SelectItem[] getItemsAvailableSelectMany() {
            return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
        }

        public SelectItem[] getItemsAvailableSelectOne() {
            return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
        }

        @FacesConverter(forClass = Writer.class)
        public static class WriterControllerConverter implements Converter {

            public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
                if (value == null || value.length() == 0) {
                    return null;
                }
                WriterController controller = (WriterController) facesContext.getApplication().getELResolver().
                        getValue(facesContext.getELContext(), null, "writerController");
                return controller.ejbFacade.find(getKey(value));
            }

            java.lang.Integer getKey(String value) {
                java.lang.Integer key;
                key = Integer.valueOf(value);
                return key;
            }

            String getStringKey(java.lang.Integer value) {
                StringBuffer sb = new StringBuffer();
                sb.append(value);
                return sb.toString();
            }

            public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
                if (object == null) {
                    return null;
                }
                if (object instanceof Writer) {
                    Writer o = (Writer) object;
                    return getStringKey(o.getWriterid());
                } else {
                    throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + WriterController.class.getName());
                }
            }
        }
    }

---------- XTMLCreate PAGE for WRITER---- **

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
    <ui:composition template="/template.xhtml">
        <ui:define name="title">
            <h:outputText value="#{bundle.CreateWriterTitle}"></h:outputText>
        </ui:define>
        <ui:define name="body">
            <h:panelGroup id="messagePanel" layout="block">
                <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/>
            </h:panelGroup>
            <h:form>
                <h:panelGrid columns="2">
                    <h:outputLabel value="#{bundle.CreateWriterLabel_writerid}" for="writerid" />
                    <h:inputText id="writerid" value="#{writerController.selected.writerid}" title="#{bundle.CreateWriterTitle_writerid}" required="true" requiredMessage="#{bundle.CreateWriterRequiredMessage_writerid}"/>
                    <h:outputLabel value="#{bundle.CreateWriterLabel_name}" for="name" />
                    <h:inputText id="name" value="#{writerController.selected.name}" title="#{bundle.CreateWriterTitle_name}" required="true" requiredMessage="#{bundle.CreateWriterRequiredMessage_name}"/>
                    <h:outputLabel value="#{bundle.CreateWriterLabel_surname}" for="surname" />
                    <h:inputText id="surname" value="#{writerController.selected.surname}" title="#{bundle.CreateWriterTitle_surname}" required="true" requiredMessage="#{bundle.CreateWriterRequiredMessage_surname}"/>
                    <h:outputLabel value="#{bundle.CreateWriterLabel_field}" for="field" />
                    <h:inputText id="field" value="#{writerController.selected.field}" title="#{bundle.CreateWriterTitle_field}" />
                </h:panelGrid>
                <br />
                <h:commandLink action="#{writerController.create}" value="#{bundle.CreateWriterSaveLink}" />
                <br />
                <br />
                <h:commandLink action="#{writerController.prepareList}" value="#{bundle.CreateWriterShowAllLink}" immediate="true"/>
                <br />
                <br />
                <h:commandLink value="#{bundle.CreateWriterIndexLink}" action="/index" immediate="true" />
            </h:form>
        </ui:define>
    </ui:composition>
</html>

**



Solution 1:[1]

I am not 100% sure but I think, you may not retrieving any results beacuse of @XMLTransiet annotation above the Serie.class method;

    @XmlTransient
    public Collection<Writer> getWriterCollection() {
        return writerCollection;
    }

I would also like to review these documents https://docs.oracle.com/javaee/6/api/javax/xml/bind/annotation/XmlTransient.html

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Caner Ar?k