6

I have a managed bean called UserSearchHandler, it has a doSearch method that populates UserSearchHandler.searchResults which are displayed in a table on the userSearch.xhtml page.

I have another managed bean called UserHandler, it has a showUser method and so on.

In the search results table, the user name is a link that, when clicked, is supposed to show user details on a userView.xhtml page. The table and link looks like this:

<p:dataTable var="user" value="#{userSearchHandler.searchResults" >

// ... and so on ... then

<h:commandLink value="#{user.firstName}" action="#{userHandler.showUser}">
  <f:setPropertyActionListener target="#{userHandler.userIdToShow}" value="#{profile.id}"/>
</h:commandLink>

Everything works fine when the managed beans are set to session scope.

However, when I change the scope on the beans to request, the search works and the table gets populated, but when I click on the name link nothing happens. I put a break point on the userHandler.showUser method and it never gets hit when the userSearchHandler is set to "request" scope.

Can anyone help explain why this is, or what I'm doing wrong?

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335

2 Answers2

5

That's because the #{userSearchHandler.searchResults} is empty during the new request and therefore JSF is unable to locate the associated row where the commandlink is been invoked in order invoke the action (and to pass/set properties if any).

You need to ensure that the same #{userSearchHandler.searchResults} is precreated during bean's construction/initialization. If it's to be created based on a specific set of parameters, then you've to pass them along with the form as well.

That's exactly the reason why solutions like Tomahawk's <t:saveState /> and new JSF 2.0 view scope exist.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks! Is there a way to make it work without making the UserSearchHandle a session-scoped bean? –  Jan 26 '11 at 15:53
  • 1
    If you're on JSF 2.0, just put bean in view scope. If you're still on JSF 1.x, consider Tomahawk's `t:saveState` (not sure if PrimeFaces offers similar inhouse solution for this though, I have never used PrimeFaces on JSF 1.x). – BalusC Jan 26 '11 at 15:55
  • Thanks again. I'm using JSF2. More questions. :) Reading about view scope, in my case I'm loading a new page "userView.xhtml" on the click. Will view scope work here or am I expected to stay on the same page for it to work? Also I'm using Spring IoC so I'm using Spring annotations to create the managed beans, like "@Scope("session")" and there doesn't appear to be a "@Scope("view")" option there. –  Jan 26 '11 at 16:18
  • Ah Spring, then it stops here. Either replace Spring by Java EE 6 CDI (if you run a Java EE 6 container), or go for the Tomahawk approach. It's pretty simple: after installing the necessary jars, add `` to the page. That's it. It behaves exactly like the view scope (which would have worked in your case, yes, the submit goes back to the same view anyway). – BalusC Jan 26 '11 at 16:21
  • More details -- and another question -- I changed my Spring annotations in the managed bean to the JSF2 ones; ex. "@Scope("session")" became "@SessionScoped" and so on. And I got the application working again (with session scoped beans). I then changed @SessionScoped to @ViewScoped and when it ran I got an error that my handler UserSearchHandler was not serializable. I added "implements Serializable" and then I got an error that there are Spring and/or Hibernate classes that are not serializable. Is this "serializable" error somethign that I can fix, or have I done something wrong? –  Jan 26 '11 at 16:37
  • Well, that's a basic design problem. Javabeans are by [specification](http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html) required to implement `Serializable`. If you don't want to serialize a javabean for some specific reason (contains sensitive information which you'd like not to store on disk or transfer over network, or contains properties which *cannot* be serialized anyway like `InputStream`, etcetera), then just mark them `transient`. The requirement of being serializable would by the way also apply when using `t:saveState`. – BalusC Jan 26 '11 at 16:39
  • Thanks again. I'm not sure what to do with "transient". I tried making my UserHandlerBean serializable, and then did "transient private UserService _userService" (which is set with a @ManagedProperty(value="#{userService}) annotation). But with the word "transient" there the userService is always null. Without the word "transient" there there is a serializable exception on "org.springframework.orm.hibernate3.AbstractSessionFactoryBean$TransactionAwareInvocationHandler" -- which presumably is used by the UserService implementation. Am I using "transient" the way you meant? Thanks again. –  Jan 26 '11 at 17:00
  • When marking a field `transient`, it won't be serialized and thus also not be availalble after deserialization. So you're using it correctly, but the `UserService` seems to be a javabean as well and it thus really needs to be serializable as well. That's just by contract. – BalusC Jan 26 '11 at 17:08
  • Just to conclude, UserService has methods (ex. createUser) that are marked @Transactional (a Spring annotation to provide Spring transaction management on the method). I can't get away from that implementation in the short term, so I'll try the t:saveState approach. In the long term, what would be the non-Spring, JavaEE-based alternative to the Spring @Transaction annotation? Thanks again. –  Jan 26 '11 at 18:00
  • Java EE/EJB is transactional by default. Note that the `t:saveState` also requires the bean to be serializable... (see also earlier comment). If the session scope or being serialiable is really no option, then you have to fiddle around with request parameters and preparing the data model in bean's constructor or `@PostConstruct` based on those parameters. – BalusC Jan 26 '11 at 18:05
0

I have a couple of ideas. If you're using a in your navigation you can try taking that out. Doing so would mean the browser will not make a new HTTP request when it renders the second window. It is the new HTTP request which clears the request scoped beans by. If that is not an option, you may be able to pass a parameter in your link such as a record id, which could allow you to pull data from your data source matching that id.

Sean
  • 971
  • 4
  • 12
  • 21
  • Unless you added ``, the navigation does by default not fire a new request. It just uses `RequestDispatcher#forward()` under the covers. It's the form submit (a pure client interaction of pressing commandlink/commandbutton) which is responsible for the new request. – BalusC Jan 26 '11 at 16:30
  • I typed redirect/ with the lt and gt carrots, but it didn't show up in my answer. Sorry about that. That's what I was trying to say. I couldn't tell if a redirect was being used or not. I read in JavaServer Faces 2.0 The Complete Reference that pressing a commandButton/Link which does not have a navigation rule with a redirect or an implicit navigation which does not include ?faces-redirect=true will simply post the form values without the browser making a second HTTP request to the new URL. – Sean Jan 26 '11 at 16:53
  • Instead, the browser will simply render the new page and the values in the request scoped bean will still be available. But I'm relatively new, so its very possible that I've misunderstood what I read. I'll go re-read it. – Sean Jan 26 '11 at 16:54