This post compares “com.sforce.soap.partner.sobject.SObject” generated by compiling Partner WSDL with WSC, to SObject class generated with Java libs like Apache Axis. This might be of interest for those developers who compiled Partner WSDL with other libs like Apache CXF etc, because this post explains the beauty of APIs exposed by WSC-SObject, so developers can compare with other compiled versions of Sobject too.
Apache Axis SObject vs WSC SObject
We will compare both on different criteria
Criteria 1: Creating SObject for a type+id and setting some field values
Here we will implement a simple API to create SObject with some Type, Id and fields using both WSC and Apache Axis. Here is the API signature/header
/**
* Creates {@link SObject} for the given params
* @param id SFDC Record ID
* @param type Type of SObject
* @param fieldValues Map of field values to set in SObject. Here Map:Key is field name and Map:Value is the field value
* @return The created Sobject with provided type,id and fieldValues.
*/
public static SObject createSObject(String id, String type,
Map<String, Object> fieldValues) {
// ..
// .. Code for Axis and WSC will go here
// ..
}
Apache Axis Implementation
public static SObject createSObject(String id, String type,
Map<String, Object> fieldValues) {
SObject sObject = new SObject();
sObject.setId(id);
sObject.setType(type);
List<MessageElement> messageElements = new ArrayList<MessageElement>();
for (String fieldName : fieldValues.keySet()) {
messageElements.add(newMessageElement(fieldName, fieldValues
.get(fieldName)));
}
sObject.set_any(messageElements.toArray(new MessageElement[] {}));
return sObject;
}
/*
* Helper method to create a single field value for Axis Sobject
*/
public static MessageElement newMessageElement(String name, Object value) {
MessageElement me = new MessageElement("", name);
try {
me.setObjectValue(value);
Element e = me.getAsDOM();
e.removeAttribute("xsi:type");
e.removeAttribute("xmlns:ns1");
e.removeAttribute("xmlns:xsd");
e.removeAttribute("xmlns:xsi");
me = new MessageElement(e);
return me;
} catch (Exception e1) {}
return null;
}
WSC Implementation
public static SObject createSObject(String id, String type,
Map<String, Object> fieldValues) {
SObject sobj = new SObject();
sobj.setId(id);
sobj.setType(type);
for (String fieldName : fieldValues.keySet()) {
sobj.setField(fieldName, fieldValues.get(fieldName));
}
return sobj;
}
Winner
For sure WSC with just 4 lines of code as compared to what we need to do with Apache Axis. With Apache Axis you have to do so much complex stuff. Even I have faced OutOfMemory error with Axis, when creating many SObjects all together, fix for that OOM error explained here
Criteria 2: Fetching field values from SObject already loaded via Partner.query(SOQL) call
Here we will use same SOQL query with both Axis and WSC, so that we can compare the ease of fetching attributes or relationships
SOQL :
static String SOQL = "Select FirstName, LastName, Account.Name, "
+ "AccountId, (Select Id, Title, Body From Notes) From Contact "
+ "where AccountId != null and Id = 'your-contact-id'";
Apache Axis Implementation
public static void main(String[] args) {
// .. create partner binding here
// Assuming you have already created a Partner Stub for Axis
QueryResult qr = partnerStub.query(SOQL);
// Contact Sobject
SObject conSObj = qr.getRecords(0);
// Axis gives Sobject fields in form of MessageElement instances
MessageElement[] conFields = conSObj.get_any();
System.out.println(" FirstName: " + parseText(conFields, "FirstName"));
System.out.println(" LastName: " + parseText(conFields, "LastName"));
// Load the Account lookup sobject from Contact.
SObject accountSobj = (SObject) parseNestedSObj(conFields, "Account");
MessageElement[] accFields = accountSobj.get_any();
System.out.println(" Account-Name: " + parseText(accFields, "Name"));
// For child relationships you get QueryResult again
QueryResult notes = (QueryResult) parseNestedSObj(conFields, "Notes");
for (SObject note : notes.getRecords()) {
MessageElement[] noteFields = note.get_any();
System.out.println("Note Id : " + note.getId());
System.out.println("Note Title :" + parseText(noteFields, "Title"));
System.out.println("Note Body :" + parseText(noteFields, "Body"));
}
}
public static String parseText(MessageElement[] elements, String name) {
for (MessageElement e : elements)
if (name.equals(e.getName()))
return e.getValue();
return null;
}
public static Object parseNestedSObj(MessageElement[] elements,
String parentName) {
Object so = null;
for (MessageElement e : elements)
if (parentName.equals(e.getName()))
so = e.getObjectValue();
return so;
}
WSC Implementation
// Assuming Partner Connection Already created till here
QueryResult query = stub.query(SOQL);
SObject conSobj = query.getRecords()[0];
// getField() method is key to get anything from Sobject
System.out.println(" FirstName: " + conSobj.getField("FirstName"));
System.out.println(" LastName: " + conSobj.getField("LastName"));
XmlObject account = (XmlObject) conSobj.getField("Account");
System.out.println(" Account-Name: " + account.getField("Name"));
XmlObject notes = (XmlObject) conSobj.getField("Notes");
Iterator<XmlObject> notesC = notes.getChildren();
while (notesC.hasNext()) {
XmlObject nextChild = notesC.next();
if (!nextChild.getName().getLocalPart().equals("records")) continue;
System.out.println("Note Id : " + nextChild.getField("Id"));
System.out.println("Note Title :" + nextChild.getField("Title"));
System.out.println("Note Body :" + nextChild.getField("Body"));
}
Winner
For sure again is WSC, with just a single SObject->getField() method from WSC’s SObject, one can seamlessly work with every field like primitive, lookup and child relationships. With Axis you for sure need to create a utility class, that will have methods similar to parseText(), parseNestedObj() etc
Conclusion
You guys can easily say WSC is for sure a clear winner, with super easy to use API. This really saves life of a developer from writing wrapper classes or utils for working over Sobject. The behavior/methods exposed by SObject are really good. For ex. I really felt comfortable as developer in using the methods like
“SObject->setField(“<FieldName>”, <Value>)” : Simply sets an attribute in Sobject.
“SObject->getField(“<FieldName>”)” : Retrieves the primitive values, lookups/references and child relationships of an Sobject field.
Leave a Reply