May 19, 2008

Spring extensible XML and web controllers

So, having got spring XML config extensions working quite nicely, I thought I’d have a go at another area of our codebase that’s been bugging me.

We have a few areas where we re-use the same MVC controller many times, with a different command and a different view. So the config looks something like this:

<bean name="/view/userbreakdown.htm" id="userBreakdownController" class="">
        <property name="commandClass" value=""/>
        <property name="statsView" value="hitLogUserBreakdownView"/>

<bean name="/view/ipbreakdown.htm" id="ipBreakdownController" class="">
        <property name="commandClass" value=""/>
        <property name="statsView" value="hitLogIPBreakdownView"/>

... continue for many more HitLogStatsControllers...

Hmm, I thought, would’t this be nicer if we could just say

   <stats:controller name="/view/all.htm" id="summaryController" command="HitLogStatsSummaryCommand" view="hitLogAllView"/>


Well, it turns out to be harder than you might think. As you can see from the bean definitions, we’re using the BeanNameUrlHandlerMapping to let SMVC map requests onto controllers. This relies on setting the name attribute of a bean to the URL you want (You can’t use the ID, because slashes are illegal for ID attributes). N.b. this is an attribute of the bean def; not a property of the bean.

So, we need to set the bean name. But, this doesn’t appear possible using
NamespaceHandlerSupport. The name isn’t actually an attribute of the BeanDefinition itself, rather it’s part of the BeanDefinitionHolder class. You set it using the 3-arg constructor of BeanDefinitionHolder. Alas, all beans defined by non-default XML have their BeanDefinitionHolders created for them in AbstractBeanDefinitionParser.parse, which calls the 2-arg version of the constructor (which doesn’t set a beanName). Default XML elements, by comparison, are created in BeanDefinitionParserDelegate, which uses the 3-arg version.

So, can we fix it? Making the custom parsing code call the 3-arg constructor would involve ripping a great deal of the guts of the XML parsing code out; not something I’d be too keen on. Maybe I should raise a JIRA with the Spring MVC team.

An easier solution might be to write a different HandlerMapping, that used a bean property (“path”, say) rather than bean names/aliases to store the URL path in. This strikes me as a nicer solution (not least because it doesn’t overload the bean name with behaviour that’s nothing to do with names), though I don’t know whether it would perform as well ( lookups presumably get cached,though, so it would be a one-off cost).

Alternatively, I could convert the one-controller-several-commands model into several ThrowawayControllers (all inheriting a common base), and then use the annotation-based config to set them all up. This seems like it might be a neater long-term solution, so long as there’s nothing that’s too expensive to set up in the controllers (which can’t be pushed out into an injected service).

- 3 comments by 1 or more people Not publicly viewable

  1. Rusty

    With the new 2.5 annotations you can annotate different methods in the same controller to handle different urls. See section 13.11.3 of the spring reference manual. After using this annotation stuff for spring mvc I’ll never go back to the xml stuff.

    19 May 2008, 19:08

  2. Chris May

    Yeah, I know about that. Unfortunately, we need different sets parameters binding for each different command, so using one controller wouldn’t really work (unless we just added a gazillion fields onto the giant controller object and bound whichever ones we wanted, but that seems kinda ugly and the validation would be hard).

    19 May 2008, 19:27

  3. Chris May

    “sets parameters” above should read “sets of parameters”. doh.

    19 May 2008, 19:28

Add a comment

You are not allowed to comment on this entry as it has restricted commenting permissions.

Most recent entries


Search this blog

on twitter...


    Not signed in
    Sign in

    Powered by BlogBuilder
    © MMXXI