Konstantin Milyutin
Konstantin Milyutin

Reputation: 12366

XmlRpcClientException: An invalid XML character (Unicode: 0x8) was found

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

Answers (1)

Ahmed Akhtar
Ahmed Akhtar

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

Related Questions