SAXParseException: -1:-1: Premature End Of File - Misleading error
Today I had to look at a piece of code a colleague had written, using my XPathAccessor class. She used it in a servlet which gets XML formatted requests. As those are generated by an external 3rd party tool we agreed on some XML schema definitions. Everything they send us needs to conform to its corresponding schema, each reply we send gets validated against a different set.
In order to allow independent testing on either side, we provided a little test kit that allows testing our system without having to set up a servlet engine. Basically it just takes a file, reads it into a String and hands that to the handler.
First it gets parsed without validation. This is necessary to find out which type of request we were send (the address is the same for all of them). After the root element is known, it will be read again, this time using the right schema to verify the request.
Once that is done, some reply is put together and sent back to the client. So far, so good.
When I looked at the code I could see nothing wrong. Nevertheless each time a request was sent, we got a
2008-01-21 10:02:12,889 INFO [STDOUT] [Fatal Error] :-1:-1: Premature end of file. org.xml.sax.SAXParseException: Premature end of file. at org.apache.xerces.parsers.DOMParser.parse(Unknown Source) at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
I had a look at the source of the XML input and first suspected a superfluous CR-LF after the closing element of the root tag. On the net some people claimed that this might be a cause for the error above. But removing that did not help.
This is the relevant code that handles the request:
public String readXmlFromStream(InputSource anInputSource) { String tResult = null; try { XPathAccessor reader = new XPathAccessor(anInputSource); String type = reader.xp("rootElem", "reqType"); if (type.startsWith("K")) { Schema schemaK = XElement.getSchema(this.getClass() .getResourceAsStream("/schema/K.xsd")); XPathAccessor validatingReader = new XPathAccessor(anInputSource, schemaK); ...
The last line throws the "Premature end of file" SAXParseException. The constructors of XPathAccessor look like this:
public XPathAccessor(InputSource aSource) throws SAXException, IOException, ParserConfigurationException { this(aSource, null); } public XPathAccessor(InputSource aSource, Schema aSchema) throws SAXException, IOException, ParserConfigurationException { Validator validator = null; builder = factory.newDocumentBuilder(); document = builder.parse(aSource); if (aSchema != null) { validator = aSchema.newValidator(); validator.validate(new DOMSource(document)); } }
Curiously in case of the Servlet no files are involved at all. Everything is in memory, so "Premature end of file" is not too helpful anyway. The solution to this mess can be found - sometimes it turns out to be helpful - in the API documentation for the InputSource:
An InputSource object belongs to the application: the SAX parser shall never modify it in any way (it may modify a copy if necessary). However, standard processing of both byte and character streams is to close them on as part of end-of-parse cleanup, so applications should not attempt to re-use such streams after they have been handed to a parser.
This last sentence is the clue: Because the InputSource has been used to find out the type of request, it cannot be used again for the validating XPathAccessor. In that light the error message at least makes a little sense: The underlying stream has been read to its end and been closed, so one might call that the "end of file"; and because the (2nd) XPathAccessor has just tried to read it from the start, "premature" might be a valid qualifier...
Knowing that also explained why the test suite worked fine; it read the XML contents into a String, which another set of overloaded constructors for XPathAccessor can accept. Of course strings can be read as often as you like, so no problems there.
As the docs do not give an immediate hint, I hope someone finds this post to save him/her some time.
Comments
arxidia mas eipes re papara
Just created two streams from the same source, and used at different places...and magic!
I'm facing same error. I have two methods one invokes webservice with HttpClient and gets XML in response and returns response as inputStream. Second method takes InputStream as an parameter and parses xml. In the first method I'm not able to see XML as a response. Any pointers to resolve this exception?
Thanks a lot!
Tried to (re)parse an InputStream and recieved similar exception.
Based on your hints I solved this issue by parsing the InputStream for the top level node (/*). Further parsing may be done relative to top level node, e.g. ./Data/@value.
Thanks - Frank
That was really informative.
But i m kinda stuck in a same situation and not able to resolve.
If you could provide me with some pointers on it.
http://www.coderanch.com/t/546316/Web-Services/java/Getting-Exception-Premature-End-file
Thanks a lot
Thanks.
You just saved me some debugging time. Receive some well-deserved karma points from here.
Ribhu Bhaskar
out = response.getWriter(); Then i did my transform with
transformer.transform(xmlStreamSource, new StreamResult(out)); followed by what i though was harmless. [out.flush() and out.close()]. this article was a lifesaver. oddly though, it was working for over year as is then started going belly up and didn't know how to fix, removing those out.flush/close did the trick.
return (xPath.evaluate(xPathExpression, new InputSource(new StringReader(body))));
I just made the like -
InputSource inputSource = new InputSource(new StringReader(body));
(xPath.evaluate(xPathExpression, inputSource));