Strange Days, Indeed

On my current project, I was adding a closure to a taglib that displayed a link conditionally, based on the current logged-in user’s role. The taglib is referenced on every page of the application, as it is included in the main Sitemesh layout. For the purpose of this example, a user cannot have both of the roles mentioned below.

Originally, the code looked something like this:

	def user = User.findByUsername(SecurityUtils?.getSubject()?.getPrincipal())
	def roles = user?.roles
	roles.each { role->
		if(role.name == RoleNames.CUSTOMER) {
			out << " | ${link(controller:'customer', action:'showProfile'){'View Profile'}}"
			return
		}
		else if (role.name == RoleNames.SALES){
			out << " | ${link(controller:'agent', action:'showProfile'){'View Profile'}}"
			return
		}
	}

The first issue I ran into was a LazyInitializationException while attempting to use the each closure on my list of roles. Apparently, there was a JIRA opened about this.

Since the taglib is part of the Sitemesh layout, it doesn’t keep the hibernate session alive long enough to provide support for lazy fetching of child objects. This is easily overcome with some eager fetching of the child objects – this case, roles.

Now, the code has turned into something like this:

	def user = User.createCriteria().list() {
		and {
			eq('username',SecurityUtils?.getSubject()?.getPrincipal())
		}
		fetchMode('roles', FM.EAGER)
	}

Obvious problem here – I’m expected a single result, but I’m using ‘list()’ instead of ‘get()’. Sorry. It took a minute to figure out. I’m using ‘list()’, I’ve learned my lesson, I’m getting back a result set, and it’s going to be some sort of a list. In other instances I’ve done the same thing, and since the result is not statically typed, I’m expecting I’ll just get whatever the first result is.

Simple enough.

But, something else happened here. In the each closure on roles, ‘role’ was also being interpreted as a list. The code above was failing.

It seems that when you’re eager fetching using ‘list()’, the parent object and all the children (even the singular instances accessed in the each closure) are treated as lists. To function correctly, the code had to be changed to this:

	roles.each { role->
		if(role[0].name == RoleNames.CUSTOMER) {
			out << " | ${link(controller:'customer', action:'showProfile'){'View Profile'}}"
			return
		}
		else if (role[0].name == RoleNames.SALES){
			out << " | ${link(controller:'agent', action:'showProfile'){'View Profile'}}"
			return
		}
	}

That doesn’t seem as clear to me as it could be. A brief conversation with some co-workers, and changing:

		def user = User.createCriteria().list() {

to:

		def user = User.createCriteria().get() {

got things back to normal for us. The comparisons then became:

	if(role.name == ... 

If anyone else has had a similar experience to the one above or an explanation of this behavior, I’d like to hear about it!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s