ColdFusion MX webservice implementations as CFCs may include optional input arguments, however consuming the webservice may prove tricky if those optional parameters are not included.

For example, consider this example webservice having one required argument (a1) and one optional argument (a2):

Webservice Producer

view plain print about
1[cfcomponent>
2
3 [cffunction name="test1" access="remote" returntype="string" output="No">
4 [cfargument name="a1" required="Yes">
5 [cfargument name="a2" required="No" default="2">
6    
7 [cfreturn "It worked!">
8 [/cffunction>
9
10[/cfcomponent>


Now consider how you might consume the webservice while only passing the required argument a1:

Webservice Consumer (Typical Syntax)
view plain print about
1[cfinvoke webservice="http://localhost/webservice_optargs.cfc?wsdl" returnvariable="result" method="test1">
2 [cfinvokeargument name="a1" value="1">
3
4[/cfinvoke>


Webservice Consumer (Alternate Syntax)
view plain print about
1[cfobject webservice="http://localhost/webservice_optargs.cfc?wsdl" name="ws">
2[cfset result = ws.test1(a1=1)>


The problem with each of these is than an error will occur which seems completely contradictory, hinting that the webservice method could not be found.

view plain print about
1Web service operation "test1" with parameters {a1={1},} could not be found.
2
3The error occurred in /opt/coldfusionmx/wwwroot/serat/webservice_client.cfm: line 11
4
511 : [cfobject webservice="http://localhost/webservice_optargs.cfc?wsdl" name="ws">

612 : [cfinvokeargument name="a1" value="1">
713 :
8
9coldfusion.xml.rpc.ServiceProxy$ServiceMethodNotFoundException: Web service operation "test1" with parameters {a1={1},} could not be found.
10 at coldfusion.xml.rpc.ServiceProxy.invoke(ServiceProxy.java:136)


In brief, this is a Java "method not found" exception. Yet if you simply uncomment the second cfinvokeargument for a2 suddenly the webservice will work. I'll try to explain why the error occurs and how to solve this problem ...

When ColdFusion consumes a webservice the first time it initially generates a "stub" which acts as a Java interface to the remote webservice, according to the WSDL specification. The stub is composed of multiple Java classes, and one of those classes contains a method which corresponds to the webservice method and its arguments. In this example, the stub interface (found in CFusionMX7/stubs/) contains the following method signature:

view plain print about
1public String test1(Object a1, Object a2)


Under the hood, the cfinvoke consumer syntax with just one cfinvokeargument subtag (omitting the optional argument) is translated to a Java method call test1(a1), and since a Java method is partly defined by the arguments that it takes the JVM then throws an exception because the method signature is actually test1(Object a1, Object a2) not test1(Object a1). Hence, the ServiceMethodNotFoundException.

The solution for this problem was introduced in ColdFusion MX 7.0 with an optional attribute omit="(yes|no)" for the cfiinvokeargument tag. When calling the example webservice and passing the required argument a1 only then you must use a [cfinvokeargument name="a2" omit="yes"> without a value to properly invoke the webservice. Effectively, this causes ColdFusion to make the Java method call test1(a1, a2) where a2 is null, and this matches the the method signature test1(Object a1, Object a2).

The CFML invocation could include some logic to determine how to properly call the webservice under the conditions where optional arguments may not be sent:

Webservice Consumer (Corrected Typical Syntax)
view plain print about
1[cfset variables.arg1 = 1>
2<br/><br/>[cfinvoke webservice="http://localhost/webservice_optargs.cfc?wsdl" returnvariable="result" method="test1">
3 [cfinvokeargument name="a1" value="#variables.arg1#">
4 [cfif isdefined("variables.arg2")>
5 [cfinvokeargument name="a2" value="#variables.arg2#">
6 [cfelse>
7 [cfinvokeargument name="a2" omit="yes">
8 [/cfif>
9[/cfinvoke>


Unfortunately, the syntax to pass optional arguments as nulls does not exist for the tag CFOBJECT or the function createObject().

From the cfinvokeargument documentation:
[cfinvokeargument name="argument name" value="argument value" omit = "yes" or "no">

You can omit a parameter by setting the cfinvokeargument omit attribute to "yes". If the WSDL specifies that the argument is nillable, ColdFusion MX sets the associated argument to null. If the WSDL specifies minoccurs=0, ColdFusion MX omits the argument from the WSDL. However, CFC web services must still specify required="true" for all arguments.

omit Optional attribute, default is "no"

Enables you to omit a parameter when invoking a web service. It is an error to specify omit="yes" if the cfinvoke webservice attribute is not specified. "yes": omit this parameter when invoking a web service. "no": do not omit this parameter when invoking a web service.