I've a data table as below:
<h:dataTable value="#{bean.items}" var="item">
I'd like to populate it with a collection from the database obtained from a service method so that it is immediately presented when the page is opened during an initial (GET) request. When should I call the service method? And why?
Do it in bean's @PostConstruct
method.
@Named
@RequestScoped
public class Bean {
private List<Item> items;
@Inject
private ItemService itemService;
@PostConstruct
public void init() {
items = itemService.list();
}
public List<Item> getItems() {
return items;
}
}
And let the value
reference the property (not method!):
<h:dataTable value="#{bean.items}" var="item">
<h:column>#{item.property}</h:column>
</h:dataTable>
Or when you merely want to iterate without autogenerating HTML:
<ui:repeat value="#{bean.items}" var="item">
#{item.property}<br />
</ui:repeat>
In the @PostConstruct
you have the advantage that it's executed after construction and dependency injection. So in case that you're using an EJB to do the DB interaction task, a @PostConstruct
would definitely be the right place as injected dependencies would not be available inside a normal constructor yet. Moreover, when using a bean management framework which uses proxies, such as CDI @Named
, the constructor may or may not be called the way you expect. It may be called multiple times during inspecting the class, generating the proxy, and/or creating the proxy.
At least do not perform the DB interaction job in the getter, unless it's lazy loading and you really can't do anything else. Namely, it would be invoked during every iteration round. Calling the service method during every iteration round is plain inefficient and may end up in "weird" side effects during presentation and postbacks, such as old values from DB seemingly still sticking around in the model instead of new submitted values.
If you rely on GET request parameters, then use <f:viewParam>
and <f:viewAction>
instead. See also Creating master-detail pages for entities, how to link them and which bean scope to choose.
If you want to preserve the model (the items
property) across postbacks on the same view (e.g. CRUD table/dialog), then make the bean @ViewScoped
, else the model won't be in sync with the view when the same model is concurrently edited elsewhere. See also Creating master-detail table and dialog, how to reuse same dialog for create and edit.
If you utilize JPA's @Version
feature on the model, then you can catch OptimisticLockException
to deal with it and show a message like "The data has been edited by someone else, please refresh/review if the desired changes are as intended". See also Letting the presentation layer (JSF) handle business exceptions from service layer (EJB).