.zugiart

Software Engineering, buddhism, and everything else in between.

apache xml-rpc handling null/nil

by zen on July 18, 2011, 2 comments

If you have used xml-rpc extensively, you will know that one of the most annoying aspect of XML-RPC is the fact that NULL values are not supported as part of the core spec. This is an issue, because NULL is such a key concept in the mainstream languages such as Python, Java and .NET – not to mention that NULL is also a supported data type in mainstream relational DB such as MySQL and Postgres. This means that if you write an xml-rpc service that publishes a data service on top of a database, your code have to handle what to do with NULL values that are stored in the db.

For this, we rely on the vendor extension. Now, Python’s extension uses <nil />. Jayrock’s .NET xml rpc extension for null is also <nil />. However for Apache’s xml-rpc implementation, the null extension is expressed as <ex:nil />. If you have stumbled across this, fear not. You CAN tell apache xml-rpc to use both <nil /> and <ex:nil /> for Null:

XmlRpcTypeNil : The implementation

import org.apache.ws.commons.util.NamespaceContextImpl;
import org.apache.xmlrpc.common.TypeFactoryImpl;
import org.apache.xmlrpc.common.XmlRpcController;
import org.apache.xmlrpc.common.XmlRpcStreamConfig;
import org.apache.xmlrpc.parser.NullParser;
import org.apache.xmlrpc.parser.TypeParser;
import org.apache.xmlrpc.serializer.NullSerializer;
import org.apache.xmlrpc.serializer.TypeSerializer;
import org.xml.sax.SAXException;
 
/**
 * This class extends Type Factory Impl to provide concrete type factory for handling
 * Null values. In this case the tag comparison uses NullSerializer.NIL_TAG as opposed
 * to EX_NIL_TAG
 *
 * @author zsugiart
 *
 */
public class XmlRpcTypeNil extends TypeFactoryImpl {
 
	public XmlRpcTypeNil(XmlRpcController pController) {
		super(pController);
	}
 
	public TypeParser getParser(XmlRpcStreamConfig pConfig, NamespaceContextImpl pContext, String pURI, String pLocalName) {
		if (NullSerializer.NIL_TAG.equals(pLocalName) || NullSerializer.EX_NIL_TAG.equals(pLocalName) )return new NullParser();
		else return super.getParser(pConfig, pContext, pURI, pLocalName);
	}
 
	public TypeSerializer getSerializer(XmlRpcStreamConfig pConfig, Object pObject) throws SAXException {
		if (pObject instanceof XmlRpcTypeNil) return new NullSerializer();
		else return super.getSerializer(pConfig, pObject);
	}
}

Client & Server configuration

The most important thing here is the XmlRpcController’s setTypeFactory method. Also remember that both XmlRpcClient and XmlRpcServer extends from XmlRpcController. Which means:

On the client end..

XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL("http://xmlrpc.url");
 
XmlRpcClient client = new XmlRpcClient();
client.setTypeFactory(new XmlRpcTypeNil(client)); // yes it's this easy!
client.setConfig(config);
 
// client.execute(...)

And on the server end…

XmlRpcServer xmlRpcServer = this.webServer.getXmlRpcServer(); // or however it is setup
xmlRpcServer.setTypeFactory(new XmlRpcTypeNil(this.xmlRpcServer));

Conclusion

This is such a simple trick, but it took me a while to work out how to work the apache xml-rpc API to make it do this. The benefit is also quite significant, with this implementation alone, we now can enable NULL data to be transported transparently between xml-rpc services implemented in Python, Java, .NET and other implementation that supports <nil /> for Null.

  • Boris

    Works great! This is just what I needed.

  • Laurent

    Thank you very much for this post!