Monday, March 28, 2011

FF obeys the rules and Spring 3 chokes

It's really quite sad/annoying when a toolkit as sophisticated as Spring chokes on simple matters.

I'm writing a GWT client to make RPC (XML/HTTP) calls to the server which is implemented in Spring MVC. My Controller has a @RequestBody on the input type which is a class that is annotated with JAXB annotations to serialise/deserialise from XML. Therefore my Controller is at the mercy of the HttpMessageConverter that Spring uses to rip the data out of the HTTP request, turn it into a POJO and give it to my Controller.

In the Spring config (I use the XML config), the <mvc:annotation-driven/> by default registers an instance of AnnotationMethodHandlerAdapter which (among other duties) is responsible for determining which message converter to use. What is nice is that a JAXB converter is registered automatically if the JAXB libs are on the classpath. The converter that is chosen is the one that can process the MIME type or Content-Type that is in the HTTP request header. In this case it would be application/xml which is processed by the default MarshallingHttpMessageConverter which in turn delegates the real work to JAXB.

However Firefox (FF) obeys the rules regarding XHR requests, in that it appends to the Content-Type header a charset. So application/xml becomes application/xml; charset=UTF-8. Because of this the entire server side code unravels because the Content-Type is not smart enough to parse the charset out of the Content-Type header; and throws an exception that the Content-Type is not recognised.

The solution after much reading up on the internals of the Spring MVC framework is to create my own bean tree where the supported type contains the charset. The message converters support changing the supported MIME types, which are modelled by the class MediaType. MediaType supports a Charset in its constructor. Therefore I end up with the following config.

<!-- Override default AnnotationMethodHandlerAdapter that
mvc:annotation-driven provides -->
<bean class="org.springframework.web.servlet.mvc.
annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="stringHttpMessageConverter" />
<ref bean="marshallingHttpMessageConverter"/>
</list>
</property>
</bean>

<bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.
MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxbMarshaller" />
<property name="unmarshaller" ref="jaxbMarshaller" />
<property name="supportedMediaTypes">
<list>
<!-- This handles browsers like FF who add
the charset to the XHR request. -->
<bean class="org.springframework.http.MediaType">
<constructor-arg index="0" value="application"/>
<constructor-arg index="1" value="xml"/>
<constructor-arg index="2" value="UTF-8"/>
</bean>
</list>
</property>
</bean>

<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.
StringHttpMessageConverter"/>

<oxm:jaxb2-marshaller id="jaxbMarshaller"
contextPath="org.altaregomelb.sync.domain"/>

Given the framework for converting data from HTTP requests already contains the logic to parse out Content-Type from the header, it's a shame that the default beans that are created by the <mvc:annotation-driven/> don't parse the charset properly instead of throwing an exception, given that it is part of the standard to include a charset in XHR requests. All XML/HTTP requests wont be XHR requests it's true, but given the prevalence of AJAX apps out there; the framework should account for it.

References
Spring 3 API

Thursday, February 24, 2011

Technological justice

In The Age today, it's reported that the Federal court backed iiNet. Finally some sane and reasonable justice from the courts in technological matters.

Well done iiNet.

Wednesday, February 2, 2011

How to prepopulate your GAE dev_server for testing

This post assumes that you know how the Google App Engine Datastore basically works, and how to perform local unit testing of your code on the dev_server provided in the GAE SDK.

There is a massive gaping hole in the GAE SDK, both in terms of functionality and documentation (of course if there is some documentation on the matter please post it in the comments) in regards to the population of your local datastore (which is persisted to a file) for testing. Why does this matter? For integration, or acceptance testing. Not all testing my Google Overlords wants to be done in a memory only datastore, or within the one process/JVM/however Eclipse runs my dev_server and my JUnit tests.

Even if you setup your test code to point to the same file that your dev_server is reading from, your application wont see your entities. To say it's a frustrating problem is an understatement. Turns out there is a combination of fields that have to be set in your test code for the underlying datastore code to populate the file in such a way to get this to work

Rather than repeat the solution, it can be on the ever helpful Stack Overflow

This solution was found though a lot of pain, trial and error. I hope someone gets a use out of this post to prevent them agonising over the amount of blood lost from when their head hit the desk screaming "why Google why!!!!"

Friday, January 21, 2011

How to beat the competition by being more agile

Over at Forbes there's a discussion about how Facebook beat MySpace. The simple solution I got out of that was Facebook is more agile, but that they also priotise customer input. Enough users want something, Facebook gives it to them (and one would assume as fast as possible). That's responding to change, obviously a key Agile principle.

Makes me think about how doing business might continue to change over the years. The suits and the bean counters may want to do one thing (lots of Powerpoint presos with forecasts), and the techs on the ground might only be thinking three months ahead - getting the latest feature out the door. There's something to be said for long term vision but do short term sprints take precedence? After all the company has to make money to keep the suits in a job.

One thing Facebook does need to do is focus on quality. To much of it breaks (and often non deterministically). The fact that I can't invite friends to an event now for three days means something's going dreadfully wrong. Since you listen to customers Facebook, can you please fix your defective parts as well as push out the latest and greatest features?

Wednesday, December 22, 2010

Holidaying with Android Froyo

Over the Christmas break, my wife wants to do some traveling. Which is all good and well, except that I have some coding that I want to. I'm sure that a lot people experience this problem.

My biggest annoyance was the lack of internet to look up API docs/reference material on the road for some tech that I want to dabble with. So I considered getting a 3G wireless modem.

Last week, my HTC Magic got upgraded to Froyo (2.2.1 actually), which of course comes with the ability to tether via USB to my computer. A quick google found instructions on how to enable the tethering on Gentoo Linux. A quick kernel config and module compile; followed by some bash scripting to modprobe cdc_ether, rndis_host and usbnet - and I had a usb0 interface sitting next to my eth0 interface. DHCP takes care of getting an IP address from the phone and I'm connected. If you're a Gentoo user, you should symlink /etc/init.d/net.lo to /etc/init.d/net.usb0 like net.eth0 for a convenient startup/shutdown script. One of the best bits is that the phone charges off the USB as well so I'm not draining the battery.

I even used my tethered connection to load Vodafone's coverage map for where we're going to show to my wife. Though knowing Vodafone the best laid USB tethering plans of mice and men are oft to go awry

Monday, November 22, 2010

Moving On

Today I've started at another company Intunity. Despite having to brush up on my Mac skills :p, this should be fun.

Wednesday, October 20, 2010

Separating out container concerns for unit testing

I got a request - come help me with these failing unit tests. The cause? The dreaded Null Pointer Exception. A member variable wasn't initialised in the constructor, but in in an init() method annotated with javax.annotation.PostConstruct. The inital impulse was to call init in the tests, but this would have led to other problems as other member variables would try to acquire container resources via JNDI (and a ServiceLocater pattern), and since this is a unit test we are mocking those dependencies. The better idea is to factor the initialisation of the attributes that are needed all the time into the constructor (which solved the NPE problem), and those attributes that are holding container resources into the @PostConstruct method since the container will honour the annotation; whereas in the unit test we can setup up the dependencies with mocks. A nice little trick but one that's very powerful.

A better approach is of course to use a DI framework, but that still doesn't get around a bad design. Separating container concerns into a @PostConstruct method (and using constructor injection perhaps) makes the class more testable with the tests taking the responsibility for being the container.