Reputation: 489
I'm Developing a JSF application using JPA 2 EclipseLink. I need to use a ListDataModel implementation of my list instead of the normal List implemettaion. I want to put this method in an abstract facade class so that it is available through the whole application. For a normal List implementation the abstract class
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
The abstract class implementation is:
@Stateless
public class ExportFacade extends AbstractFacade<Export> {
@PersistenceContext(unitName = "GazpromModulePU")
private EntityManager em;
@Override
protected EntityManager getEntityManager() {
return em;
}
public ExportFacade() {
super(Export.class);
}
This results from the method above are being correctly displayed and everything works fine. Now I want to do exactly the same thing but return the results in a ListDataModel. I tried:
public ListDataModel<T> findAllListDataModel() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return new ListDataModel<T>(getEntityManager().createQuery(cq).getResultList());
}
Using the same implementation (and the above abstract method), the list is not displayed and the error console is blank.I can manually hardcode the ListDataModel using a method like this:
public ListDataModel<Export> hardCodedMethod() {
if(someList == null) {
someList = makeModel();
}
return someList;
}
public ListDataModel<Export> makeModel() {
List<Export> elist = myFacade.findAll();
ListDataModel<Export> model = new ListDataMOdel<Export>(eList);
return model;
}
I would like to implement the above code in an abstract class instead of hardcoding it throughout the application. Would appreciate any guidance at all . Thanks in advance!
Upvotes: 0
Views: 675
Reputation: 1109665
You're in first place not supposed to have any JSF artifact in a service class. This tight-couples your business tier to the current web tier. In other words, your business tier is not reusable across different web tiers, such as RESTful, Websockets, plain JSP/Servlet, etc.
Don't change your service class. Keep returning List
from it. Make sure that you don't have any import javax.faces.***
line in any service class. Solve your problem in the JSF side instead. E.g. create an abstract backing bean.
public abstract class ListDataModelBacking<T> {
private transient ListDataModel<T> model;
public abstract List<T> getListFromService();
public ListDataModel<T> getModel() {
if (model == null) {
model = new ListDataModel<>(getListFromService());
}
return model;
}
}
Note that the DataModel
implementations are supposed to be not serializable.
Then you can use it as below in a regular backing bean:
@Named
@ViewScoped
public class FooBacking extends ListDataModelBacking<Foo> implements Serializable {
@Inject
private FooService fooService;
@Override
public List<Foo> getListFromService() {
return fooService.listAll();
}
}
<h:dataTable value="#{fooBacking.model}" ...>
Alternatively, punch the ListDataModel
and look for a simpler solution to the concrete functional requirement you tried to solve with having a ListDataModel
property in bean. Perhaps EL 2.2 capability of passing method arguments? See also a.o. How can I pass selected row to commandLink inside dataTable?
Upvotes: 1