I use Myfaces CODI #ViewAccessScoped backing beans in my JSF application. One of the
benefits is that I don't need to use view parameters to communicate information between
views. For the record #ViewAccessScoped ensures that a bean is accessible until until the first request of a new view doesn't access it. Take this case where I want to pass a string value from page1 to page2:
Page1Bean.java (backing bean for page1.xhtml)
#Inject private Page2Bean page2Bean;
private String source = "Hello, World!";
...
page2Bean.setTarget(source);
Page2Bean.java (backing bean for page2.xhtml)
private String target;
If I navigate directly from page1 to page2, then when I access #{page2Bean.target} from
page2 it has the value "hello, world!".
In effect I'm pushing the data from the page1 view to the page2 view. The other option is
to pull the data from the page1 view into the page2 view, so in the page2Bean I #Inject
Page1Bean and #ViewAccessScoped ensures that I can access page1Bean.getSource() (as long
as it was in the previous view).
This is all well and good, but in the real world I may want to navigate from page1 to any
one of a number of other pages, depending on user input. So Page1Bean.java ends up looking
like this:
Page1Bean.java (revised)
#Inject private Page2Bean page2Bean;
#Inject private Page3Bean page3Bean;
#Inject private Page4Bean page4Bean;
#Inject private Page5Bean page5Bean;
#Inject private Page6Bean page6Bean;
#Inject private Page7Bean page7Bean;
#Inject private Page8Bean page8Bean;
Now for my question: does the memory footprint of page1Bean always include page2Bean-
page8Bean? or will memory only be used if I access one of the #Inject'ed beans at
runtime?
I hope this isn't too naive a question, but I'm not sure exactly how it will work and
if the answer to the first question is yes, I'm more or less ending up using
#SessionScoped!.
Thanks for any clarification.
Well, I suppose it was pretty obvious really but having put some logging in the constructors of the beans that were being injected with #Inject, I could see that they were all being instantiated when the Page1Bean was instantiated, i.e. when navigating to page1. I found the solution in the JSR-299 CDI spec section 5.6 Programmatic lookup:
#Inject private Instance<Page2Bean> page2BeanDynamic;
...
if(someCondition) {
Page2Bean page2Bean = page2BeanDynamic.get();
page2Bean.setTarget(source);
}
so this is basically dynamic #Inject and ensures that I'm only instantiating the beans
at runtime when needed.
Putting finalize() & #PreDestroy methods in Page2Bean I see them both called when
navigating from page2 to page1, as expected.
No real memory footprint. Only proxies are generated. That's the reason for the constructor calls. You don't need to resolve beans manually!
You don't have to inject all beans. You are using it in a wrong way. Just keeping state between _ independent _ pages should be done via #WindowScoped. If they aren't independent use the beans in the target page (if you don't need the view-controller callbacks in the target pages).
Related
This question already has answers here:
How to choose the right bean scope?
(2 answers)
Closed 2 years ago.
I'm trying to implement JSF backing beans using CDI beans as suggested by the depreciation of #ManagedBean and it's scope annotations, but I'm struggling with the right use examples, I'm trying to implement view backing bean with #Model (javax.enterprise.inject.Model) which is #Named #RequestScoped.
I found this question but it's using a ViewScope bean, how would I implement the same functionality with RequestScoped (Preferably #Model), What is best practice use of #Model in general?
Edit 1:
I tried creating a new Product in the EditProduct PostConstruct:
#Model
public class EditProduct {
private Product product; // +getter +setter
#Inject
private ProductService productService;
#PostConstruct
public void init(){
product = new Product();
}
public String save() {
productService.save(product);
return "/products?faces-redirect=true";
}
// ...
}
and then setting the product via
<f:viewParameter name="product-id" target="#{editProduct.product}"
converter="#{productConverter}" />
it's working but I'm looking for a best practice.
A request scoped backing bean is meant to keep the application memory footprint as low as possible hence using them for supporting views with #Model annotation makes a lot of sense, the draw back is having to reach for the persistence data storage on every request that deals with data so a best use case for #Model bean is:
Basically every thing.
things like:
Events handling for JSF pages
Lazy loading of data
Validation and converting and other code execution
ETC.... yes every thing else
Those things are easily done best in request scoped beans, but then what are the roles of other beans?
In simplistic terms we can assume:
#ViewScoped to support data heavy pages where user edits data with many interactions and each interaction is a request but hitting the database for each one will be costly.
#SessionScoped for session data, authentication, credentials and configuration for the user.
#ApplicationScoped the state-full singleton of CDI.
.... each other scope has it's uses, but for a good web application #Model should be the default and the others has specific uses cases.
You should be able to also add the #Named annotation and it will be exposed as editProduct.
https://memorynotfound.com/cdi-managed-bean-example-with-named/
EDIT: See comment
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?
Call it before page is loaded. But how?
Call it during page load. How?
Call it in the getter method. But it is called multiple times.
Something else?
Do it in bean's #PostConstruct method.
#ManagedBean
#RequestScoped
public class Bean {
private List<Item> items;
#EJB
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">
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).
See also:
Why JSF calls getters multiple times
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
How to choose the right bean scope?
JSF Controller, Service and DAO
All of my pages are backed their own ViewScoped bean, but I'm finding that there are a lot of similar methods used on these pages. For example, a user may want to view dates in their preferred time zone so each time a page is loaded, the DB is queried for what their preferred time zone is.
So my initial thought was to create a ViewScoped bean to manage this. The timeZone value would be only be "good" for the lifetime of the page and they would be lazy-loaded to avoid unnecessary database hits:
#Named
#ViewScoped
public class Preference implements Serializable {
#Inject
private SessionManager sessionManager;
#EJB(name = "PreferencesReadFacade")
private PreferencesReadFacadeRemote prefReadFacade;
private HashMap<String, Object> cache = new HashMap<>();
/**
* #return the user's TimeZone preference
*/
public String getTimeZone() {
if(cache.get("TimeZone") == null) {
cache.put("TimeZone", prefReadFacade.getUserPreference(sessionManager.getUserId(), "TimeZone").toString());
}
return cache.get("TimeZone").toString();
}
}
Usage:
<h:outputText value="#{preference.timeZone}"/>
Is there anything wrong with this type of methodology? Is there a better way of doing something like this?
EDIT: Would like to add that I'm using ICEfaces and Omnifaces so if there are resources in these libraries at my disposal, I'm certainly open to using those.
Your approach is bsolutely correct - you may reuse the same bean in multiple pages regardless of its scope. If those pages are in the same scope, a bean would be reused, otherwise a new bean would be created with an empty cache. If the scope is ViewScoped, the bean would be recreated for every page, hence DB would be accessed first when the data is needed on after a page loads.
You may also make your common bean a base bean of other viewscoped beans, which are constructed for a particular page (they must remain viewscoped).
Or, you may inject your Preference bean into any other Named bean, which is used in your pages. In this way, you may inject it to a bean with any scope, but CDI will always give you the same bean for a view (within viewscope), but different when you redirect to a new page.
But your solution is equally correct, if not even better.
You can create one #SessionScoped bean and hold there user preferences like time zone. Then #Inject it to your #ViewScoped beans and get time zone from #SessionScoped. As long as http session lives, the DB query will be done only once in the user session if you do it in #PostConstruct and assign to variables.
Im new to web programming so this is a beginner question.
In my web application which is a maven project with JSF framework(university project), I have some pages with just text that displays various information about my fake air line company(only consists of <p> and <h1>). Now, to my question. Should I just "hard code" the information on the JSF Page or should I use beans to get my text and titles from?
The information that will be on my info pages will remain the same and never change.
If this question is inappropriate to ask here, please let me know and Ill remove it.
Since you've stated that the information will never change, storing it in a string in the bean class would work, and use getter methods to retrieve the data
#ManagedBean
#SessionScoped
public final class Airlineimplements Serializable
{
private static final long serialVersionUID = 47493274L;
private String title = "Air Canada";
private String headquarters = "Toronto Ontario Canada";
public Airline()
{
}
public String getTitle()
{
return title;
}
public String getHeadquarters()
{
return headquarters;
}
}
This is #RequestScoped so that you retrieve the information on each request and the information is garbaged after the request.
A #RequestScoped bean will be garbaged by end of every request and recreated on every new request.
Full answer here about #ViewScoped vs #RequestScoped
Difference between View and Request scope in managed beans
Although this should be #SessionScoped which keeps the information for the life of the session.
For the Serializable UID, the serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to ensure that the caller and receiver of a Serialized object have the same loaded classes.
More information about Serializable
http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
Here are some additional tutorials on JSF for beginners
http://www.tutorialspoint.com/jsf/
http://www.vogella.com/tutorials/JavaServerFaces/article.html
I have two beans. First bean languageOfSystem:
#Named(value = "languageOfSystem")
#SessionScoped
public class LanguageOfSystem implements Serializable {
#Inject private JsfUtils eeJsfUtils;
and the second bean, userBb:
#Named(value = "userBb")
#SessionScoped
public class UserBb implements Serializable, LangUpdInterface {
#EJB
private EjbUtils ejbUtils;
#EJB
private PuserFacade puserFacade;
#Inject
private Direction direction;
#Inject
private PortfelDao portfelDao;
#Inject
private LanguageOfSystem languageOfSystem;
I inject languageOfSystem into userBb, and NetBeans IDE gives me warning in line with that injection:
no enabled eligible for injection beans are found
But I'm able to call methods from languageOfSystem in userBb and it works fine. So is this warning important and should I change smth?
And the second question. I use in this case observer design pattern, where userBb is dependent and languageOfSystem is the subject which has a list of dependents. I register userBb in subject list by calling appropriate method from languageOfSystem. Is it right when it comes to the two session beans?
But I'm able to call methods from languageOfSystem in userBb and it
works fine.
Your code does not look wrong - and it works. So this seems to be a Netbeans issues.
And the second question. I use in this case observer design pattern,
where userBb is dependent and languageOfSystem is the subject which
has a list of dependents. I register userBb in subject list by calling
appropriate method from languageOfSystem. Is it right when it comes to
the two session beans?
Are you aware that the CDI spec includes a powerful and typesafe implementation of the observer pattern? You definitely should check this out.
And two more things to mention here:
#Named(value = "languageOfSystem")
#Named(value = "userBb")
The value you are providing is already default. So you can leave it
out and simply write #Named instead.
Regarding the code you are posting: #Named is not required at all -
all it does is providing an EL name for use in JSF. Your code will
work just as good if you skip #Named altogether...
As to your first question:
This is a known netbeans bug (see here and here). However, the discussion in the first link indicates that it is rather an issue of the weld implementation and Netbeans' warning is according to the specification.
Nevertheless the bugzilla file says it will be fixed in Netbeans v7.2.
Until then you can still disable the warning (Tools --> Options --> Editor --> Hints)