Reputation: 12366
I'm using Apache XML-RPC library to get bugs from Bugzilla. Calling the service, I receive exception: org.apache.xmlrpc.client.XmlRpcClientException: Failed to parse server's response: An invalid XML character (Unicode: 0x8) was found in the element content of the document.
Is there a way to understand where exactly mistake is. I located a date of bugs, which causes mistake. But there are a lot of them. Can I print the received xml or make exception more precise?
Upvotes: 4
Views: 4571
Reputation: 1463
Its late but in case someone stumbles upon this.
Edit:
I have been on this for two months now and finally I have found a viable solution to the above problem.
This issue occurs because Bugzilla::Webservice sometimes, in response to a, remote procedure call, sends an invalid character in the XML response.
When Apache's XML-RPC tries to parse that response, it gives the following error:
XmlRpcClientException: An invalid XML character (Unicode: 0x8) was found
To solve this issue, Apache's XML-RPC Client needs to be extended to clean the response off invalid XML characters before trying to parse it.
Find the source code of apache-xmlrpc as an Eclipse project here. (Import this project instead of the jar files)
To do this, we first need to extend the BufferedReader
class to replace any invalid XML character before it returns.
So, add /apache-xmlrpc-3.1.3-src/client/src/main/java/org/apache/xmlrpc/client/util/XMLBufferredReader.java
, like this:
package org.apache.xmlrpc.client.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
/**
* @author Ahmed Akhtar
*
*/
public class XMLBufferredReader extends BufferedReader
{
/**
* @param in
*/
public XMLBufferredReader(Reader in)
{
super(in);
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException
{
int ret = super.read(cbuf, off, len);
for(int i = 0; i < ret; i++)
{
char current = cbuf[i];
if(!((current == 0x9) ||
(current == 0xA) ||
(current == 0xD) ||
((current >= 0x20) && (current <= 0xD7FF)) ||
((current >= 0xE000) && (current <= 0xFFFD)) ||
((current >= 0x10000) && (current <= 0x10FFFF))))
{
cbuf[i] = 'r';
}
}
return ret;
}
}
Later, we need to send in the extended XMLBufferedReader
to the InputSource
of the parse
method.
The function readResponse
in the file /apache-xmlrpc-3.1.3-src/client/src/main/java/org/apache/xmlrpc/client/XmlRpcStreamTransport.java
needs to be changed to:
protected Object readResponse(XmlRpcStreamRequestConfig pConfig, InputStream pStream) throws XmlRpcException
{
BufferedReader in = new XMLBufferredReader(new BufferedReader(new InputStreamReader(pStream, StandardCharsets.UTF_8)));
InputSource isource = new InputSource(in);
XMLReader xr = newXMLReader();
XmlRpcResponseParser xp;
try {
xp = new XmlRpcResponseParser(pConfig, getClient().getTypeFactory());
xr.setContentHandler(xp);
xr.parse(isource);
} catch (SAXException e) {
throw new XmlRpcClientException("Failed to parse server's response: " + e.getMessage(), e);
} catch (IOException e) {
throw new XmlRpcClientException("Failed to read server's response: " + e.getMessage(), e);
}
if (xp.isSuccess()) {
return xp.getResult();
}
Throwable t = xp.getErrorCause();
if (t == null) {
throw new XmlRpcException(xp.getErrorCode(), xp.getErrorMessage());
}
if (t instanceof XmlRpcException) {
throw (XmlRpcException) t;
}
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
throw new XmlRpcException(xp.getErrorCode(), xp.getErrorMessage(), t);
}
After this extension to the Apache's XML-RPC Client, everything should work fine.
Note: The rest of this post, is the initial solution that I posted, which is a workaround in case someone does not want to extend Apache's XML-RPC client.
Old Post:
In case you are using the Bugzilla::Webservice::Bug::search utility function with some offset
and limit
parameters along with the search criteria.
You would be getting this exception on some specific values lets say x
of offset
and y
of limit
which you can find out by running in debug mode.
Now call the search
function by keeping x
as offset and 1
as limit
and then loop and increment x
until it reaches a value of x + y
as offset while still keeping limit
as 1
.
This way you will be extracting bugs one at a time and running in debug mode you can determine the exact bug which is causing the exception.
For x = 21900
and y = 100
do something like:
for(int i = 21900; i <= 22000; i++)
{
result = ws.search(searchCriteria, i, 1);
}
Running this in debug mode I found out that the actual offset
causing the bug was 21963
so then I wrote code to avoid that specific bug:
if(offset != 21900)
{
result = obj.search(productNames, offset, limit);
bugsObj = (Object[])result.get("bugs");
}
else
{
result = obj.search(productNames, 21900, 63);
Object[] bugsObj1 = (Object[])result.get("bugs");
result = obj.search(productNames, 21964, 36);
Object[] bugsObj2 = (Object[])result.get("bugs");
bugsObj = new Object[bugsObj1.length+bugsObj2.length];
for(int i = 0; i < bugsObj1.length + bugsObj2.length; i++)
{
bugsObj[i] = i < bugsObj1.length ? bugsObj1[i] : bugsObj2[i - bugsObj1.length];
}
}
Upvotes: 1