function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
jchanowitzjchanowitz 

Custom Class Mapping from Web Service Client to Apex Code

I'm trying to use the Value Object design pattern to call an Apex Code web service method to save a non-trivial object graph into the database.  My client is Flex / Flex Toolkit.  I create an SObject in the client, using the name of the custom class I've created in my Apex class, something like: 
 
.  I then pass that object as a parameter to
jchanowitzjchanowitz

Oops. Don't know why my previous message posted while I was editing it....

Anyways, when the Apex method receives my parameter, it thows an error saying my custom apex class does not have attribute "type."  I can't add a "type" attribute to my class because 'type" is reserved, and I guess is used for proxy kind of services.  Is there any way I can do this?

Thanks.

DevAngelDevAngel
Hi Jay,

The flex toolkit did not support that ability, although the platform is perfectly capable of handling Apex defined classes as arguments to Apex webService methods.  We are in the process of publishing a new version of the toolkit that does support this.

Here is a sample of perfectly valid Apex webService configuration and usage.

Code:
Apex webService Class and Method:

global class webServices {
 webService static String classObjectTest(ValueObject vo) {
  //Simply echo the object back to the caller
  return 'Class object test: Success \n' + vo.toString();
 }
}

Apex Class used as webService argument:

global class ValueObject {
 
 webService String fieldOne;
 webService String fieldTwo;
 webService ChildValue child;
}

Apex Class used as nested child object:

global class ChildValue {
 
 webService String childFieldOne;
 webService String childFieldTwo;
 
}

Flex/ActionScript invocation of the Apex webService:

private function callWebService():void {
 var responder:AsyncResponder = new AsyncResponder(handleResults, handleFault);

 //Create dynamic class to represent Apex Class
 var vo:ObjectProxy = new ObjectProxy();
 vo.fieldOne = "field one";
 vo.fieldTwo = "field two";
    
 //Add the nested Apex class (ChildValue)
 vo.child = new ObjectProxy();
 vo.child.childFieldOne = "child field one";
 vo.child.childFieldTwo = "child field two";
    
 //Set parameter name and value
 var param1:Parameter = new Parameter("vo", vo);

 //Execute the Apex Web Service passing in the nested object
 apex.execute("webServices", "classObjectTest", [ param1 ], responder);
}
private function handleResults(res:Object):void {
 Alert.show("Web service call was successful:\n" + ObjectUtil.toString(res));
}


A couple of things to note about the code and pattern above. 
  • The webService must be declared as global as described in the documentation.
  • The classes used as arguments to the web service (even if the class is referenced indirectly) must also be declared global.
  • The fields that are exposed to the web services client must be declared webService.  You might have many other fields that are used in the class, but only the ones declared webService will be serializable and deserializable.
That's it.  This is a powerful aspect of the Apex language and a pattern that should prove very useful.



Cheers



jchanowitzjchanowitz

Very nice!  I assume that arrays map across as well?

How do you announce when the new Toolkit is posted?

Ron HessRon Hess
you can RSS this page
http://sourceforge.net/project/showfiles.php?group_id=96634&package_id=225227

i updated the library today to pick up this feature and one bug fix on Bitmap.as
DevAngelDevAngel
Hi Jay,

Arrays, huh?  Not to sound pithy, but the documentation for Apex specifies what Apex types can and can't be used in this situation.

From page 124 of the Reference Guide:

Because there are no SOAP analogs for certain Apex Code elements, methods defined with the webService keyword cannot take the following elements as parameters.While these elements can be used within the method, they also cannot be marked as return values.

• Maps
• Sets
• Pattern objects
• Matcher objects
• Exception objects



I don't actually see that you cannot use an array.  What the statement above says is that if there is an analog for an Apex type in SOAP (ie. can be represented in SOAP/XML) then it is a valid type to pass.

If you do try an array, can you let us know how it went?

Cheers

SuperfellSuperfell
Arrays are supported.
jchanowitzjchanowitz

I can confirm that they do map from the flex client into Apex.

Nice job guys.  That was really a fast turnaround.

Thanks again.

MiddhaMiddha

Hi Simon,

 

Can you please confrim if 2D arrays are supported. While trying to return a 2D array i am getting "Circular Object Graph detectobject ed during serialization, you cannot have circular object references in an Apex Web Service response." error in my client application.

 

/G