There is an other option suggested here
However I resolved Extending a ContentNegotiatingViewResolver and overriding the resolveViewName method, I called my ViewResolver HttpHeaderParamViewResolver. The extended method looks something like this:
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
//Get the HTTP Header param "User-Agent"
String headerParamValue = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getHeader(headerParam);
viewName = setViewName(viewName, headerParamValue);
return super.resolveViewName(viewName, locale);
}
Where headerParam="User-Agent" (or any other HTTp Header parameter you like, this is defined in the bean xml), after that you evaluate it and determine the viewName. In My case the HttpHeaderParamViewResolver can be configured with a Map where the key is a prefix to be appended to the actual viewName and the value is a RegExp that will be used to evaluate the value of the header param. It looks something like this in the App Context XML:
<bean id="HttpHeaderViewResolver" class="com.application.viewresolver.HttpHeaderParamViewResolver">
<property name="viewResolvers">
<list>
<ref bean="tilesViewResolver"/>
</list>
</property>
<property name="headerParam" value="User-Agent"/>
<property name="viewPrefixPattern">
<map>
<entry>
<key>
<value>mobile-webkit</value>
</key>
<value>iPhone.*Apple.*Mobile.*Safari</value>
</entry>
<entry>
<key>
<value>mobile-bb</value>
</key>
<value>BlackBerry([0-9]{0,4})([a-zA-Z])?</value>
</entry>
</map>
</property>
</bean>
That way the if my controller calls a view called userDetails and is accessing the application with an IPhone the first pattern catchs it and appends the mobile-webkit suffix so the view is now mobile-webkit-userDetails and its then passed to the tilesViewResolver which generates the actual view.
I explored a lot of possibilities and I think this is the easiest and most flexible I was able to came up with. In this case the ability to choose an entire different view was critical because we support a wide variety of user agents, from WAP to IPhone 4 and WebKit capable mobiles, so views change dramatically from user agent to user agent. Other advantage is that you no longer require to handle this issue on the view since you can have views as specialized as you like. Other bright side is that you can implement this quite easily without having to remove or change the view resolvers you might already have since ContentNegotiatingViewResolver has the ability to delegate the view call to other view resolvers in the specific sequence you define.
The down side is that you may be tempted to over specialize the views and end up with a ton of view files rendering the app a maintainable nightmare.
Hope it is helpful.