Home > Oracle Service Bus, XPath, XQuery > OSB’s Custom XPath functions and NULL values

OSB’s Custom XPath functions and NULL values

Oracle Service Bus features a nice possibility to write custom XPath functions. Eric already blogged about it some time ago.
Recently we stumbled upon an interesting question: How can NULL values of basic types be transferred from Java to XQuery and back? Is it even possible? The short story: No, it isn’t.

As is known, there is no explicit NULL in XQuery. There are empty sequences, and you can mark an element with the xsi:nil attribute to represent NULL: <elem xsi:nil="true"/>. But there is no NULL-equivalent for basic data types.

Nevertheless, I checked how OSB’s XQuery implementation behaves, if one tries to transfer null values. Here is the result:

First, we write three Java methods, taking a string parameter and returning null, an empty string and a whitespace-string.

package com.trivadis.osb.xpath;

public class NullInXQuery {

	public static String retNull(String arg) {
		System.out.println("retNull(): arg: '" + arg + "'");
		return null;
	}
	
	public static String retEmpty(String arg) {
		System.out.println("retEmpty(): arg: '" + arg + "'");
		return "";
	}
	
	public static String retSpace(String arg) {
		System.out.println("retSpace(): arg: '" + arg + "'");
		return " ";
	}
}

Add an entry for each method in the configuration XML:

<?xml version="1.0" encoding="UTF-8"?>
<xpf:xpathFunctions xmlns:xpf="http://www.bea.com/wli/sb/xpath/config">
    <xpf:category id="Testing Null behaviour Functions">
        <xpf:function>
            <xpf:name>retNull</xpf:name>
            <xpf:namespaceURI>http://trivadis.com/osb/nullinxquery</xpf:namespaceURI>
            <xpf:className>com.trivadis.osb.xpath.NullInXQuery</xpf:className>
            <xpf:method>java.lang.String retNull(java.lang.String)</xpf:method>
            <xpf:isDeterministic>true</xpf:isDeterministic>
            <xpf:scope>Pipeline</xpf:scope>
            <xpf:scope>SplitJoin</xpf:scope>
        </xpf:function>
        <xpf:function>
            <xpf:name>retEmpty</xpf:name>
            <xpf:namespaceURI>http://trivadis.com/osb/nullinxquery</xpf:namespaceURI>
            <xpf:className>com.trivadis.osb.xpath.NullInXQuery</xpf:className>
            <xpf:method>java.lang.String retEmpty(java.lang.String)</xpf:method>
            <xpf:isDeterministic>true</xpf:isDeterministic>
            <xpf:scope>Pipeline</xpf:scope>
            <xpf:scope>SplitJoin</xpf:scope>
        </xpf:function>
        <xpf:function>
            <xpf:name>retSpace</xpf:name>
            <xpf:namespaceURI>http://trivadis.com/osb/nullinxquery</xpf:namespaceURI>
            <xpf:className>com.trivadis.osb.xpath.NullInXQuery</xpf:className>
            <xpf:method>java.lang.String retSpace(java.lang.String)</xpf:method>
            <xpf:isDeterministic>true</xpf:isDeterministic>
            <xpf:scope>Pipeline</xpf:scope>
            <xpf:scope>SplitJoin</xpf:scope>
        </xpf:function>
	</xpf:category>
</xpf:xpathFunctions>

Finally call the functions within a ProxyService’s log action:

<x>
<null>{nulo9:retNull(<elem xsi:nil="true"/>)}</null>
<empty>{nulo9:retEmpty("")}</empty>
<space>{nulo9:retSpace(" ")}</space>
</x>

As you can see, we try to pass a nilled element to the Java method (hoping it will be converted to null). Further we pass an empty string and a string containing whitespace only.The methods themselves return null, an empty string and a whitespace-string.

After you execute the ProxyService, you will see the following in the stdout log file:

retNull(): arg: ''
retEmpty(): arg: ''
retSpace(): arg: ' '
<17.10.2010 22:58 Uhr MESZ> <Debug> <ALSB Logging> <BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage1, REQUEST] <x>
  <null/>
  <empty/>
  <space></space>
</x>>

So, there seems to be no way to pass null between Java and XQuery in either direction. null will always be converted into an empty string, the same applies to a nilled element.

For other basic data types, the situation seems to be somewhat inconsistent. For instance, if you try the same with a custom XPath function taking and returning java.lang.Integer, you will receive the following error if you call the custom XPath function with a <elem xsi:nil="true"/> parameter value:

weblogic.xml.query.exceptions.XQueryDynamicException: {err}XP0021: "": can not cast to {http://www.w3.org/2001/XMLSchema}integer: error: decimal: Invalid decimal value: expected at least one digit

The same Java method returning a java.lang.Integer null leads to:

weblogic.xml.query.exceptions.XQueryTypeException: line 5, column 28: {err}XP0006: "0 ({http://www.w3.org/2001/XMLSchema}integer)": bad value for type {http://www.w3.org/2001/XMLSchema}int

For java.sql.Date, however, the situation looks similar at first. For a method taking and returning java.sql.Date, passing <elem xsi:nil="true"/> leads to:

weblogic.xml.query.exceptions.XQueryDynamicException: {err}XP0021: "": can not cast to {http://www.w3.org/2001/XMLSchema}date: error: date: Invalid date value: wrong type

But the same Java method returning a java.sql.Date null in contrast runs smoothly!

If somebody knows a practical and consistent way to pass null between Java and XQuery, you are welcome to add a comment!

About these ads
  1. Dave
    March 7, 2011 at 5:33 pm

    I was getting the Invalid date value error for DateTime. The solution is to call unset on the value that is null.

    For example:
    if (purchaseNotificationDate == null) {
    if (annuityAccount.isSetPurchaseNotificationDate()) {
    annuityAccount.unsetPurchaseNotificationDate();
    }
    }

  2. Paul
    July 20, 2011 at 7:22 pm

    I think you can pass xs:nil – it’s a constructor.

    I had to do this when using Oracle’s XMLTable expression where a resulting NUMBER column needed to be set to null.

  3. February 20, 2013 at 5:44 am

    Exactly how long did it require you to publish “OSBs Custom
    XPath functions and NULL values | JMischa”? It contains
    a good deal of fantastic information and facts. Appreciate it -Gilbert

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: