Wednesday, October 22, 2008

Grails Conditional Tags as Method Calls Trap

As you probably know grails tags can also be used within controllers as method calls. In this post I will describe the trap that caught me when I tried to use conditional tag within if statement.

Default usage of grails tag as method call can be described with the following example. g.render tag within gsp page will look like this:

<g:render template="someTemplate" model:[name:"peter"]/>

While within controller you can use this tag like this:

g.render(template:"someTemplate", name:"peter")
I must admit that this is excellent feature of the grails and I use it often. But you can get confused if you try to use conditional tags within if statements. Lets try one example.

Imagine that we have following conditional tag userHasGoldMembership that displays its content only when logged in user has gold membership. Usage of this tag within gsp page may look like this:

...
<g:userHasGoldMembership>
<g:link controller="abc" action="xyz">Perform this action</g:link>
</g:userHasGoldMembership>
...

What example does is that link 'Perform this action' will be displayed only if logged in user has gold membership.

Now let us try to use this tag as method call within controller as condition within if.

def price = 100
if (g.userHasGoldMembership()) {
price = price - discount
}
chargeCreditCard()

Well to my surprise what happens here is that g.userHasGoldMembership() always resolves to false. And after some thinking it becomes clear why this happens. Let us analyze how in the most cases conditional tags work. For example, for mentioned conditional tag implementation may look like this (and I believe this is the case for the majority of conditional tags):

class MembershipTagLib {
def userHasGoldMembership = {attrs, body ->
if (session.user.isGold()) {
out << body()
}
}
}

What we see in this code is that in the case that user has gold membership returned value from the tag will be body of the tag. In all other cases nothing is returned. But what is body within construct if(g.userHasGoldMembership())?

Well there is no body. This means that in both cases, user has and user has not gold membership, result of the tag used as method call will be null.

Does it mean that we cannot use conditional tags? Of course not. It is enough to provide body. Version of the if statement that works is:

def price = 100
if (g.userHasGoldMembership() {true}) {
price = price - discount
}
chargeCreditCard()

Did you notice the {true} part? This is actually body of the tag. It means that when user has gold membership, tag will return result of body execution and that is value true.

And of course example from the real conditional tag that is probably widely used is from acegi. Acegi plugin provides tag <g:ifAllGranted role="LIST_OF_ROLES">content to display</g:ifAllGranted>. And if you want to reuse this plugin within your controller then you have to use it in the form of

if (g.ifAllGranter(role="ROLE_ADMIN"){true}) {
do something
}
otherwise you will never get into the if part of the condition.

Thursday, October 9, 2008

javax.faces.el.PropertyNotFoundException

This is another interesting bug we had in just two days. Again one of those "this is not happening to me" bugs :)

We have JSF project and on JSF projects you are creating managed beans and setting values to those beans within faces-config.xml file.

Well for one of the new managed beans we got javax.faces.el.PropertyNotFoundException. In the first moment it seemed like one of standard typo errors but after verifing the code everything seemed ok but JSF was just refusing to set value of the managed been. Again, after some googling we found solution in this post.

Well shortly, this problem occurs if you have variable in the managed bean that starts with lower-case character after which immediately follows upper-case character. So variables with the names like: xCor, xStreamConverter or similar cannot be found by JSF and finish with the
javax.faces.el.PropertyNotFoundException exception.

java.util.MissingResourceException

These days we had two very strange errors during build of project. Our build configuration is CruiseControl with Maven.
When building project locally everything worked fine while on CruiseControl we got this error:
java.util.MissingResourceException: Can't find resource for bundle com.sun.tools.doclets
.formats.html.resources.standard, key doclet.malformed_html_link_tag
First surprise was why everything works fine locally but fails on the build server. But answer we found quickly. On build server project was build with mvn clean site but locally we are mainly using mvn clean package. After using mvn site locally we got the same error. And then we started with investigation. After hours of investigation we found solution and the problem is described with this Jira issue.

Shortly, with some build versions of Java 5, generation of javadoc will fail if there is <a somewhere in java doc.

So when writing java doc avoid <a characters sequence.