For a project we are migrating some java applications to WebSphere 8.5. In the process we are trying to get rid of some legacy frameworks. One of them is shale (apache attic). The only component from shale that is used is the view controller to instantiate a request scoped jsf managed beans for every page. Every bean has an init method that is called on page load. I'd like to use #PostConstruct on this method. The only problem I have that the bean gets instantiated when a method on the bean is called. Unfortunately the bean is not always called and the init method does populate data on a session scoped bean. There is a naming convention that links pages and beans so we could use a listener to instantiate the bean based on the request. Another solution might be changing the scope to viewscope (probably to much a hassle on websphere 8.5).
I was wondering if there is something I can do to make the PostConstruct work? And are there other options I'm missing?
edit:
I have a PhaseListener in place that performs the basic functionality. It matches the requested page to the corresponding bean (by naming convention). The following is used to instantiate the bean but it looks a bit ugly.
expressionFactory.createValueExpression(elContext, "#{" + managedBeanName + "}", Object.class)
Is there a more elegant way to do this?
Perhaps you could try using <f:event/> ?
In your view, you could add this to the page.
<f:event type="postAddToView" listener="#{backingBean.myInitMethod()"/>
https://stackoverflow.com/a/14004230/4706826
Gives you info on when the events get executed.
Put a #PostConstruct annotated method in the backing bean. This annotation tells the bean to execute the annotated method every time its constructor is being called.
Example:
#ManagedBean
#ViewScoped
public class MyManagedBean{
#PostConstruct
public void initView() throws Exception{
...initialize page values, execute database queries, etc.
}
Related
At which phase of the JSF request processing lifecycle, the backing bean method marked with #PostConstruct called?
Methods marked with the #PostConstruct will be invoked after the bean has been created, dependencies have been injected, all managed properties are set, and before the bean is actually set into scope.
Found related SO thread, might not be exactly same but it answers your question. And a blog entry explaining the same.
I'm currently trying to get CDI (Weld to be more precise) to work with JSF 2 and a long running conversation. I'm starting the conversation in #ConversationScoped my backing bean. I'm also creating a #ConversationScoped entity manager. Sadly the entity I'm editing in my backing bean always get's a LazyInitializationException when JSF is trying to write a #ManyToMany mapped field. It seems that the entity get's detached from the entitymanager. In my EntityManagerProducer (see below) the method createEntityManager() is not called bevore the LazyInitializationException is thrown, so I'd assume that the entitymanager is actually session scoped. But from what I understand my code does not generate an extended persistence context (since I could not figure how to do that programmatically).
As far as I know DeltaSpike does not yet offer anything for dealing with long running conversations in JSF. Can anybody suggest a method on how to implement long running conversations with CDI using Weld + DeltaSpike (preferably on a Tomcat with weld-servlet)?
#ApplicationScoped
public class EntityManagerProducer {
#Inject
#PersistenceUnitName("myUnit")
private EntityManagerFactory emf;
#Produces
#ConversationScoped
public EntityManager createEntityManager() {
return emf.createEntityManager();
}
public void closeEm(#Disposes EntityManager em) {
em.close();
}
}
The lazy initialization exception actually does not come from extended persistence contexts or CDI or DeltaSpike. It's simply the same behaviour as described here: selectManyCheckbox LazyInitializationException on process validation
JSF 2 clones the PersistentBag of my entity causing it to get detached. I also worked around by sprinkling lot's of
<f:attribute name="collectionType" value="java.util.ArrayList" />
throughout my JSF code.
Having the EntityManager in a conversation scope is only one side of the equation, what scope are your entities in ?
In order to avoid detaching the entities they should also be conversation scoped.
As a side note :
I found that instead of dealing with entities in a long running scope , it is much easier to reattach them in each request scope.
I have a bean that does some logic, I call it logicBean,
and it has a sessionscoped bean as field with #Inject.
I use this logicbean in two situations in one JAVA EE6 Application,
1. in servlet.
2. in message driven bean.
In the second situcation, I got a excetion
"WebBeans context with scope type annotation #SessionScoped does not exist within current thread".
I know there is no sessionScope in MDB, so I made another bean, and want to
inject it to logicBean dynamicly to alternative the sessionScoped bean.
I do not know how to do this.
please help me, thanks.
Is it possible to keep a request scoped bean alive across postbacks on the same page?
The general problem is, as the bean gets trashed on end of request and recreated on every form submit, for example the booleans behind dynamically manipulated disabled, readonly and rendered get reset to their default values and cause the forms to not work as intented anymore.
I'll assume that the session scope is not an option, otherwise this question makes little sense.
You can do it using Tomahawk <t:saveState>. Add the following line somewhere to the page:
<t:saveState value="#{bean}" />
RichFaces <a4j:keepAlive> does also the same:
<a4j:keepAlive beanName="#{bean}" />
Or if there is room, upgrade to at least JSF 2.x and put the bean in view scope:
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
// ...
}
Regardless of the way, the same bean will be there when you postback to the same view and keep returning null or void from action methods.
See also:
How to choose the right bean scope?
Difference between View and Request scope in managed beans
Not really, unless you store the Bean somewhere e.g. a Map in application scope, to retrieve it later.
Why not just make it Session scoped? This is what Session scope is there for, so multiple Requests during the same Session can hit the same state.
Is it possible to get a reference to the to-be-executed managedbean in the before-invokeApplication-phaselistener ?
Before the invoke application phase, it should be clear which managedBean that is going to execute the method.
For the sake of the example, assume there's 1 main manage bean to handle 1 jsf page.
So what i need is basically :
The user access the program from the menu
Because it's accessed from the menu, the main manage bean's init() method gets called to initialize stuffs like preparing data, doing authorization checks
Subsequent submits dont need to call the init() method anymore until it's reaccessed from the menu
To implement the point #2, im thinking of intercepting one of the phases
I've checked the API docs about getting the managed bean in the phases implementation, but i couldnt seem to find any.
After typing this question, i realize i could do this in #PostConstruct or the managed bean's constructor, but that would do only at the first time the bean is constructed, and my need is to call the method everytime the jsf is being accessed from the menu.
Any suggestions ?
Regards,
Albert Kam
You can access your managed beans via the ELContext/ELResolver. This is explained nicely in the MyFaces wiki (also works in vanilla JSF).
For example:
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
NeededBean neededBean = (NeededBean) FacesContext.getCurrentInstance().getApplication()
.getELResolver().getValue(elContext, null, "neededBean");
See the MyFaces wiki entry for further explanation, and implementations for other JSF versions.
Your idea of using #PostConstruct is a good one. Consider changing your scope to something liked #ViewScoped, so the logic is executed everytime you navigate to that view.
Also, have a look at the PreRenderViewEvent (for JSF 2). This code is embedded in your facelet page:
<f:metadata>
<f:viewParam name="foo" value="#{bean.foo}"/>
<f:event type="preRenderView" listener="#{bean.doSomething}"/>
</f:metadata>
The f:event listener is executed before every page view.