Monday, May 11, 2009

Some notes on a JSF-related fix

It's late on a Friday and I've just solved a JSF headache, so I'm going to quickly write this up while it's still fresh in my mind (the solution, not the headache).

You may have stumbled onto this message if you're developing in JSF or just vanilla JSP:

#{..} is not allowed in template text

When you Google this phrase, you'll find various chunks of advice around versions of JSP, deferred expressions and the Unified Expression Language that comes with JSP 2.1. In particular, this reference appeared to have the definitive fix for my problem: either change the "#{" to "${", or backslash-escape the "#{" sequence, or change a setting to allow deferred syntax as literal. Now, any or all of these solutions might work for you, depending on your context; but I write this up because none of them worked for me.

What I have is a web application developed with JSF 1.1 that had used JSTL 1.1, but that then got deployed into a Java EE 5 environment which provides JSF 1.2 and JSTL 1.2. Many of you already know where this is going. But for my own future reference and possibly your amusement, I'm going to write it up anyway.

I changed all occurrences of #{ to ${, and knowing that Java EE 5 servers already supply the correct JSTL 1.2 version, I removed my webapp's private copies of jstl.jar and standard.jar (vestiges from when they were needed, with J2EE 1.4 servers), but now I get this error message:

According to TLD or attribute directive in tag file, attribute rendered does not accept any expressions

So the syntax change was a head-fake, at least in my case; I can't explain why. You are invited to chime in if you understand it. I was referred to one useful discussion that contains various suggested solutions and references various other threads, and it got me on the right track. Here's what I ended up doing: first, change the ${ back to #{, since really getting the incorrect JSTL version out of the way is the true fix. There is also an EL expression factory workaround discussed in that thread which was applied to my deployment descriptor.

But, here's where it gets interesting (as if it isn't already drop-dead compelling, right?) -- although removing the JSTL 1.1 stuff, applying the DD workaround and reverting back to #{ syntax should have cured all my problems, now I get an EL parsing error concerning this particular attribute construction:

text="#dds.value.enabled?isnsMsg.deactivate_action:isnsMsg.activate_action}"

This is a boolean expression managing a text value that must change depending on the state of a given backing bean property; this had worked just fine in my JSF 1.1 deployment, but now it's no good. The error reads something like this:

Was expecting one of:
"(" ...
<identifier> ...
<namespace> <identifier> "(" ...
Without belaboring the point - since I have a headache from all the different things I tried - I'll just admit it: I took the inelegant way out and used two panel-grouping blocks, each with its own rendered-if attribute, to fix this problem (I'm using tags from the Woodstock JSF component set):
<ui:panelGroup rendered="#{dds.value.enabled}">
    <ui:hyperlink text="#{isnsMsg.deactivate_action}"/>
</ui:panelGroup>
                                       
<ui:panelGroup rendered="#{!dds.value.enabled}">
    <ui:hyperlink text="#{isnsMsg.activate_action}"/>
</ui:panelGroup>
Using JSTL IF and WHEN testing is just as ugly, but at least it fails to work. The JSTL expressions get evaluated too soon relative to the JSF lifecycle, i.e. the IF and WHEN always yield false since they're evaluated before the backing bean property gets its value set as needed.

I didn't do any research to understand why the inline boolean expression in JSF 1.1 caused a parsing error in JSF 1.2 (or maybe it's a JSP 1.2 vs JSP 2.0 thing...hey, probably it's JSTL 1.1 vs 1.2...isn't web-tier fun?). So while I've solved the immediate problem, I've left plenty of room for colleagues to elaborate and, frankly, to correct me where I'm misleading. Like I say, it's late on a Friday and sometimes I do as little as necessary to get from A to Z. If anyone has additional insights around what's discussed here, you are invited to share.

No comments:

Post a Comment