1

I faced this situation quite a few times, and I found my solution but not sure if it's a good one.

I need to call some service which interacts with the database and then share the result between multiple components.

Consider this example:

<p:outputPanel id="myPanel">
  <c:set var="myVar" value="#{myService.retrieveVarFromDB(param)}" />
  <my:comp1 val="#{myVar.field1}" />
  <my:comp2 val="#{myVar.field2}" />
  <my:comp3 val="#{myVar.field3}" />
</p:outputPanel>

Here myVar could be reevaluated multiple times, upon ajax update requests. But the good thing is that myService is called only once every time, not for every component which uses myVar. Some of my colleagues do it like this:

  <my:comp1 val="#{myService.retrieveVarFromDB(param).field1}" />
  <my:comp2 val="#{myService.retrieveVarFromDB(param).field2}" />

which is a total overhead. So far my solution satisfies me, but I also know that mixing JSF with JSTL tags could sometimes cause strange things to happen. And many of our co-developers try to avoid using them.

So, is there more elegant solution to this problem without using <c:set />?

Edit:
Calculating myVar just once doesn work for me, because as I stated earlier I need to reevaluate it multiple times. For example when user chooses an item from some select component, an ajax request is sent to the server which in turn makes call to the database, reevaluating myVar value.

Edit2:
myService is actually a managed bean, which uses injected EJB reference to interact with the database. I called it this way to show what it does, but that happened to be misleading. Sorry about that.

jFrenetic
  • 5,384
  • 5
  • 42
  • 67

1 Answers1

1

Getter calls are extraordinary cheap. They're only expensive if you're doing more in a getter than just returning the property. I suggest to do the job in bean's (post) constructor instead and provide a new getter which only returns that result.

For aliasing of long EL expressions, you can always use <ui:param>.

As to mixing JSTL with JSF, they can cause view scoped beans to break and they may lead to unexpected behaviour when used in iterating JSF components such as <ui:repeat> and <h:dataTable>. JSTL and JSF namely don't run in sync as you'd expect from the coding. It's JSTL which runs first from top to bottom during JSF view build time (to create the JSF component tree) and then it's JSF which runs from top to bottom again during JSF view render time (to generate HTML).

See also:


Update, as per your edit:

Calculating myVar just once doesn work for me, because as I stated earlier I need to reevaluate it multiple times. For example when user chooses an item from some select component, an ajax request is sent to the server which in turn makes call to the database, reevaluating myVar value.

Just do that in the action listener method which is invoked by the ajax request. Do above all not abuse the getter for that.

<f:ajax listener="#{bean.itemChanged}" />

with

public void itemChanged() {
    myVar = myService.retrieveVarFromDB(param);
}

then you can use #{bean.myVar} in the view.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I'm sorry for misleading service method name. Actually `myService` interacts with the database to get the variable, so it's not just a simple getter. I corrected my question. Also, I didn't understand from your answer, whether it's a good practice to use c:set in such cases? – jFrenetic Sep 22 '11 at 18:41
  • See answer update (and the "see also" links). The service can just be injected in the managed bean so that you can do the job in bean's action method. The service (I assume it to be an EJB?) should by itself not be a JSF managed bean at all. – BalusC Sep 22 '11 at 18:43
  • So, from your answer, I concluded that using is not recommended? But what if I want to reuse my managed bean for multiple views, and only one of them needs this variable. I guess, it's not good to keep the reference to the variable in the bean in this case, isn't it? – jFrenetic Sep 22 '11 at 19:05
  • If it's not a session scoped bean, I don't forsee how that can be problematic. However, reusing the same bean in multiple views is at its own also a bit smelly. It may be right, but it may also be wrong. It could for example be the case that the bean is doing "too much" and should be split out over different beans so that each view has its own one. That all depends on the functional requirements. – BalusC Sep 22 '11 at 19:08
  • Agreed.But could you please comment on whether using c:set is considered harmful, so I can accept your answer? – jFrenetic Sep 22 '11 at 19:17
  • It's only harmful in certain conditions which I already mentioned in 3rd paragraph of my answer. In cases where it works, it is not necessarily a good practice. I personally would favour a real "JSF-ish" way. – BalusC Sep 22 '11 at 19:20
  • Thanks! Sometimes I wonder, aren't you one of JSF implementors? Because you seem to know almost everything about it :) – jFrenetic Sep 22 '11 at 19:24
  • 2
    I'm just an avid JSF user :) This experience is based on over 5 years almost daily practical experience and reading/answering JSF-related questions on (former) forums.sun.com and stackoverflow.com and also reading/reporting issues in JSF bug tracker. I have also kind of photographic memory, so that helps also a bit to remember all. – BalusC Sep 22 '11 at 19:26