Unmarshaller performance improvements in JAXB RI 2.0
The initial version of the JAXB RI unmarshaller was written for 1.0 for more than 2 years ago, and that was based on my experience working with a databinding tool called RELAXNGCC. The idea was to build a push-down automaton by using XML events as alphabets. This was very flexible, in that it can capture most of the RELAX NG grammar (such as a choice between attributes, or a choice between an element and an attribute.)
Then we started working on 2.0, and soon we decided that we shouldn't be generating all those unmarshallers and marshallers in terms of Java source code. Instead, we were to compose them from small unmarshaller "primitives", much like how you build a castle out of lego blocks. We did this porting without losing any of the expressiveness we had in the 1.0 unmarshaller.
Around the same time, we were also considering to reduce the expressiveness of the unmarshaller; in 1.0, it was possible to bind a content model like A,A to two different properties. But it was increasingly becoming clear that limiting this expressiveness is better for many reasons, such as to allow invalid documents to be unmarshalled more robustly. One nice by-product of this simplification was that the unmarshaller no longer needed the kind of expressiveness we actually implemented.
But since the unmarshaller was working, we busily worked on other unimplemented features. That left the unmarshaller unnecessarily powerful for the purpose of 2.0. I was hoping to rewrite it once again, to trade the excessive flexibility for a better performance.
And I was finally able to do this in this month. Specifically, compared to 1.0,
- 1.0 was creating a copy of attributes so that it can be processed later. 2.0 no longer does this.
- 2.0 defers the computation of raw element name (like "foo:bar") until necessary, and most commonly just avoids it altogether. Some API (like StAX) makes it expensive to compute the raw names, so this helps when we are unmarshalling from those.
- State machine model is much simplified in 2.0, resulting in smaller code size, smaller memory footprint, and smaller number of method invocations.
- Simplified state machine model made error diagnosis much easier. When 2.0 see an unexpected element, we can report what elements are expected (whereas in 1.0, we couldn't easily tell what are the allowed elements.)
I've been thinking about the design for a long time (and a jury duty helped!), so the actual implementation was easier than I thought. In terms of the performance, we got roughly 10-20% improvement on our internal benchmark, and it also reduced the footprint of JAXBContext by 15-20%.