So, I decided that the push-style event interface (Push parser) was not the ideal for what I wanted to do. Push-style interfaces like SAX are efficient, but can be harder for people to wrap their heads around to get the behavior they want. I in particular want to write a JSON <-> POJO library on top of the core, and decided that it becomes a bit harder to keep track of it all in your head using an event interface.
So, I switched to a pull-style model, which I have named JSONCursor. Every time a pertinent event (data encountered or start/end of some structured type), the parser wills top and return an ‘event’ object explaining what it found.
I also decided to raise the level of the interface quite a bit, so you get a full String object rather than being triggered as before to handle a new bit of text or escaped character, and being responsible for accumulating it all yourself to handle the event.
One of the fun things this provides is that I was able to make JSONCursor implement Iterator<JSONEvent>. Of course, iterators are normally over data structures and not data being processed, so Java did not design iterator to be able to return errors. I currently wrap errors and raise RuntimeExceptions to get around this; I may decide at some point to make all of JSONException extend RuntimeException instead.
For now, since its relatively easy to have a pull parser emulate a push-parser, I still support a SAX-style interface as well. It was the easiest way to get things up and running and testable. I will probably drop this interface in the future just because of the additional size and confusion – or move it to another package, if there is one which would be relevant.