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
SScholtzSScholtz 

Web Service WSDL: some classes not being defined in generated WSDL

Hi there,

 

I'm working on making a web service for a client and I'm running into a few issues around some classes I have defined not showing up in the WSDL.

 

I have an element, Entity, which can be many things (Artist, Company, Contract...).  The client wants to receive and send Entity objects, but objects will have different properties depending on whath they're sending.

 

I came up with the following...

 

    global virtual class Entity {

    }
    
    global class Assignment extends Entity {
        webservice String integrationID;
        webservice Date startDate;
        webservice Date endDate;
....
 } global class Artist extends Entity { webservice String integrationID; webservice String salutation; webservice String lastName; webservice String firstName; .... } global class GetUpdatedEntitiesResponse { webservice List<SynchOperation> synchOperation; } global class SynchOperation { webservice String synchID; webservice Entity entity; webservice Entity oldEntity; } webservice static GetUpdatedEntitiesResponse GetUpdatedEntities(Integer maxItems) { // Generate a List<SynchOperation> which include entity and oldEntity values;
// Since Artist and Assignment extend Entity, they can be created and safely assigned
// to SynchOperation.entity and SynchOperation.oldEntity
.... }

 

Everything above shows up defined in the WSDL except for Assignment and Artist.  Naturally, the client is looking for definitions of these.

 

I've been Googling around but haven't had much luck.  I'm not a SOAP guru, but the client needs it.  I understand that there is a concept of inheritance/extension in SOAP, but have no idea what it actually looks like in a WSDL, or if SF accomdates for this.

 

It seems like SF's web service implementation values simplicity over complexity, so my guess is no?

 

Am I doing something wrong above, or does SF just not accomadate for this scenario?

 

I have a couple of solutions in mind, either make Entity this massive class which holds all the properties of all the objects it's supposed to represent, or get rid of SynchOpertaion.entity and oldEntity, and replace it with a series of hard coded nodes, ex. SynchOperation.artist, SynchOperation.oldArtist, SynchOperation.assignment, SynchOperation,oldAssignment, etc.

 

Thoughts?

 

Thanks for your help!

 

 

Best Answer chosen by Admin (Salesforce Developers) 
SScholtzSScholtz

I got an official response from Sales Force developer support, SalesForce currently does not support any kind of SOAP inheritance.

 

Created an Idea for this, vote if you'd like to see it added: https://sites.secure.force.com/success/ideaView?id=08730000000bYanAAE

All Answers

UVUV

Can you pls post the genearted wsdl??

SScholtzSScholtz

Sure...

 

<?xml version="1.0" encoding="UTF-8"?>
<!--
 Web Services API : SynchWebService
-->
<definitions targetNamespace="http://soap.sforce.com/schemas/class/SynchWebService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://soap.sforce.com/schemas/class/SynchWebService">
 <types>
  <xsd:schema elementFormDefault="qualified" targetNamespace="http://soap.sforce.com/schemas/class/SynchWebService">
   <xsd:element name="DebuggingInfo">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="debugLog" type="xsd:string"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:simpleType name="ID">
    <xsd:restriction base="xsd:string">
     <xsd:length value="18"/>
     <xsd:pattern value="[a-zA-Z0-9]{18}"/>
    </xsd:restriction>
   </xsd:simpleType>
   <xsd:simpleType name="LogCategory">
    <xsd:restriction base="xsd:string">
     <xsd:enumeration value="Db"/>
     <xsd:enumeration value="Workflow"/>
     <xsd:enumeration value="Validation"/>
     <xsd:enumeration value="Callout"/>
     <xsd:enumeration value="Apex_code"/>
     <xsd:enumeration value="Apex_profiling"/>
     <xsd:enumeration value="Visualforce"/>
     <xsd:enumeration value="System"/>
     <xsd:enumeration value="All"/>
    </xsd:restriction>
   </xsd:simpleType>
   <xsd:simpleType name="LogCategoryLevel">
    <xsd:restriction base="xsd:string">
     <xsd:enumeration value="Internal"/>
     <xsd:enumeration value="Finest"/>
     <xsd:enumeration value="Finer"/>
     <xsd:enumeration value="Fine"/>
     <xsd:enumeration value="Debug"/>
     <xsd:enumeration value="Info"/>
     <xsd:enumeration value="Warn"/>
     <xsd:enumeration value="Error"/>
    </xsd:restriction>
   </xsd:simpleType>
   <xsd:complexType name="LogInfo">
    <xsd:sequence>
     <xsd:element name="category" type="tns:LogCategory"/>
     <xsd:element name="level" type="tns:LogCategoryLevel"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:simpleType name="LogType">
    <xsd:restriction base="xsd:string">
     <xsd:enumeration value="None"/>
     <xsd:enumeration value="Debugonly"/>
     <xsd:enumeration value="Db"/>
     <xsd:enumeration value="Profiling"/>
     <xsd:enumeration value="Callout"/>
     <xsd:enumeration value="Detail"/>
    </xsd:restriction>
   </xsd:simpleType>
   <xsd:element name="DebuggingHeader">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="categories" minOccurs="0" maxOccurs="unbounded" type="tns:LogInfo"/>
      <xsd:element name="debugLevel" type="tns:LogType"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="CallOptions">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="client" type="xsd:string"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="SessionHeader">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="sessionId" type="xsd:string"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="AllowFieldTruncationHeader">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="allowFieldTruncation" type="xsd:boolean"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:complexType name="AckOperation">
    <xsd:sequence>
     <xsd:element name="entityType" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="operationValue" minOccurs="0" type="xsd:boolean" nillable="true"/>
     <xsd:element name="synchID" minOccurs="0" type="xsd:string" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="AckOperationResponse">
    <xsd:sequence>
     <xsd:element name="ackOperationResult" minOccurs="0" maxOccurs="unbounded" type="tns:AckOperationResult" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="AckOperationResult">
    <xsd:sequence>
     <xsd:element name="entityType" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="errorCode" minOccurs="0" type="xsd:int" nillable="true"/>
     <xsd:element name="synchID" minOccurs="0" type="xsd:string" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="Entity">
    <xsd:sequence>
     <xsd:element name="integrationID" minOccurs="0" type="xsd:string" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="GetUpdatedEntitiesResponse">
    <xsd:sequence>
     <xsd:element name="synchOperation" minOccurs="0" maxOccurs="unbounded" type="tns:SynchOperation" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="SynchOperation">
    <xsd:sequence>
     <xsd:element name="entity" minOccurs="0" type="tns:Entity" nillable="true"/>
     <xsd:element name="entityType" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="oldEntity" minOccurs="0" type="tns:Entity" nillable="true"/>
     <xsd:element name="operation" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="synchID" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="updateTS" minOccurs="0" type="xsd:date" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="SynchOperationResult">
    <xsd:sequence>
     <xsd:element name="entityType" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="errorCode" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="errorMessage" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="synchID" minOccurs="0" type="xsd:string" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="UpdateEntitiesResponse">
    <xsd:sequence>
     <xsd:element name="synchOperationResult" minOccurs="0" maxOccurs="unbounded" type="tns:SynchOperationResult" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="UpdateEntity">
    <xsd:sequence>
     <xsd:element name="businessAddress" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="businessCity" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="businessCountry" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="businessState" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="businessZipCode" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="email" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="integrationID" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="mobilePhone" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="performingStatus" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="secondaryEmail" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="synchTS" minOccurs="0" type="xsd:date" nillable="true"/>
     <xsd:element name="website" minOccurs="0" type="xsd:string" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="UpdateSynchOperation">
    <xsd:sequence>
     <xsd:element name="entity" minOccurs="0" type="tns:UpdateEntity" nillable="true"/>
     <xsd:element name="entityType" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="operation" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="synchID" minOccurs="0" type="xsd:string" nillable="true"/>
     <xsd:element name="updateTS" minOccurs="0" type="xsd:date" nillable="true"/>
    </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="AckGetUpdatedEntities">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="ackOperations" minOccurs="0" maxOccurs="unbounded" type="tns:AckOperation" nillable="true"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="AckGetUpdatedEntitiesResponse">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="result" type="tns:AckOperationResponse" nillable="true"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="GetUpdatedEntities">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="maxItems" type="xsd:int" nillable="true"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="GetUpdatedEntitiesResponse">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="result" type="tns:GetUpdatedEntitiesResponse" nillable="true"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="UpdateEntities">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="synchOperations" minOccurs="0" maxOccurs="unbounded" type="tns:UpdateSynchOperation" nillable="true"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="UpdateEntitiesResponse">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="result" type="tns:UpdateEntitiesResponse" nillable="true"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
  </xsd:schema>
 </types>
 <!-- Message for the header parts -->
 <message name="Header">
  <part name="AllowFieldTruncationHeader" element="tns:AllowFieldTruncationHeader"/>
  <part name="CallOptions" element="tns:CallOptions"/>
  <part name="DebuggingHeader" element="tns:DebuggingHeader"/>
  <part name="DebuggingInfo" element="tns:DebuggingInfo"/>
  <part name="SessionHeader" element="tns:SessionHeader"/>
 </message>
 <!-- Operation Messages -->
 <message name="AckGetUpdatedEntitiesRequest">
  <part element="tns:AckGetUpdatedEntities" name="parameters"/>
 </message>
 <message name="AckGetUpdatedEntitiesResponse">
  <part element="tns:AckGetUpdatedEntitiesResponse" name="parameters"/>
 </message>
 <message name="GetUpdatedEntitiesRequest">
  <part element="tns:GetUpdatedEntities" name="parameters"/>
 </message>
 <message name="GetUpdatedEntitiesResponse">
  <part element="tns:GetUpdatedEntitiesResponse" name="parameters"/>
 </message>
 <message name="UpdateEntitiesRequest">
  <part element="tns:UpdateEntities" name="parameters"/>
 </message>
 <message name="UpdateEntitiesResponse">
  <part element="tns:UpdateEntitiesResponse" name="parameters"/>
 </message>
 <portType name="SynchWebServicePortType">
  <operation name="AckGetUpdatedEntities">
   <input message="tns:AckGetUpdatedEntitiesRequest"/>
   <output message="tns:AckGetUpdatedEntitiesResponse"/>
  </operation>
  <operation name="GetUpdatedEntities">
   <input message="tns:GetUpdatedEntitiesRequest"/>
   <output message="tns:GetUpdatedEntitiesResponse"/>
  </operation>
  <operation name="UpdateEntities">
   <input message="tns:UpdateEntitiesRequest"/>
   <output message="tns:UpdateEntitiesResponse"/>
  </operation>
 </portType>
 <binding name="SynchWebServiceBinding" type="tns:SynchWebServicePortType">
  <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
  <operation name="AckGetUpdatedEntities">
   <soap:operation soapAction=""/>
   <input>
    <soap:header use="literal" part="SessionHeader" message="tns:Header"/>
    <soap:header use="literal" part="CallOptions" message="tns:Header"/>
    <soap:header use="literal" part="DebuggingHeader" message="tns:Header"/>
    <soap:header use="literal" part="AllowFieldTruncationHeader" message="tns:Header"/>
    <soap:body use="literal" parts="parameters"/>
   </input>
   <output>
    <soap:header use="literal" part="DebuggingInfo" message="tns:Header"/>
    <soap:body use="literal"/>
   </output>
  </operation>
  <operation name="GetUpdatedEntities">
   <soap:operation soapAction=""/>
   <input>
    <soap:header use="literal" part="SessionHeader" message="tns:Header"/>
    <soap:header use="literal" part="CallOptions" message="tns:Header"/>
    <soap:header use="literal" part="DebuggingHeader" message="tns:Header"/>
    <soap:header use="literal" part="AllowFieldTruncationHeader" message="tns:Header"/>
    <soap:body use="literal" parts="parameters"/>
   </input>
   <output>
    <soap:header use="literal" part="DebuggingInfo" message="tns:Header"/>
    <soap:body use="literal"/>
   </output>
  </operation>
  <operation name="UpdateEntities">
   <soap:operation soapAction=""/>
   <input>
    <soap:header use="literal" part="SessionHeader" message="tns:Header"/>
    <soap:header use="literal" part="CallOptions" message="tns:Header"/>
    <soap:header use="literal" part="DebuggingHeader" message="tns:Header"/>
    <soap:header use="literal" part="AllowFieldTruncationHeader" message="tns:Header"/>
    <soap:body use="literal" parts="parameters"/>
   </input>
   <output>
    <soap:header use="literal" part="DebuggingInfo" message="tns:Header"/>
    <soap:body use="literal"/>
   </output>
  </operation>
 </binding>
 <service name="SynchWebServiceService">
  <documentation></documentation>
  <port binding="tns:SynchWebServiceBinding" name="SynchWebService">
   <soap:address location="https://cs9-api.salesforce.com/services/Soap/class/SynchWebService"/>
  </port>
 </service>
</definitions>

 

 

 

SScholtzSScholtz

And here's the SynchWebServices class, edited for brevity and with some dummy test code in place that will eventually be replaced with some SOQL queries and such...

 

global class SynchWebService {

    /****************** ENTITIES ************************************/
    global virtual class Entity {
        webservice String integrationID;
    }
    
    global class Assignment extends Entity {
        webservice String integrationID;
        webservice String artistIntegrationID;
 ....
    }
    global class Artist extends Entity {
        webservice String integrationID;
        webservice String salutation;
        webservice String lastName;
        webservice String firstName;
        webservice String middleName;
....
    }
    global class ArtistPicture extends Entity {
        webservice String integrationID;
        webservice String artistIntegrationId;
        webservice String pictureURL;
    }
    global class Contract extends Entity {
        webservice String integrationID;
....
        
    }
    global class ContractLineItem extends Entity {
        webservice String integrationID;
        webservice String contractIntegrationId;
....
    }
    global class Submittal extends Entity {
        webservice String integrationID;
        webservice String artistIntegrationID;
        webservice String showIntegrationId;
        webservice String positionIntegrationId;
    }
    global class Role extends Entity {
        webservice String integrationID;
        webservice String name;
        webservice String showProjectId;
    }
    global class Position extends Entity {
        webservice String integrationID;
....
    }
    global class Company extends Entity {
        webservice String integrationID;
        webservice String name;
        webservice Boolean status;
    }
    
    
    








    /****************** GET UPDATED ENTITIES ************************/
    // Classes that define outgoing bits
    global class GetUpdatedEntitiesResponse {
        webservice List<SynchOperation> synchOperation;
    }

    global class SynchOperation {
        webservice String synchID;
        webservice String entityType;
        webservice Datetime updateTS;
        webservice String operation;
        webservice Entity entity;
        webservice Entity oldEntity;
    }
    
    webservice static GetUpdatedEntitiesResponse GetUpdatedEntities(Integer maxItems) {

        // Test code....
        List<Artist> artistList_Updated = new List<Artist>();
        List<Artist> artistList_Old = new List<Artist>();
        
        List<SynchOperation> mySynchs = new List<SynchOperation>();

        for (Integer i = 1; i <= maxItems; i++) {
            Date ds = Date.today();
            String y = String.valueOf(ds.year());
 
            Artist a = new Artist();
            a.integrationID = 'artist-' + i + ' ' + ds.year() + '-' + ds.month() + '-' + ds.day();
            a.salutation = 'Mr.';
            a.lastName = 'Scholtz';
            a.firstName = 'Stephen';
            a.middleName = 'Matthew';
 ....
            
            artistList_Updated.add(a);
            artistList_Old.add(a);
            
            SynchOperation aSynch = new SynchOperation();
            aSynch.synchID = (i+100) + ' ' + ds.year() + '-' + ds.month() + '-' + ds.day();
            aSynch.entityType = 'artist';
            aSynch.operation = 'update';
            aSynch.entity = a;
            aSynch.oldEntity = a;
            
            mySynchs.add(aSynch);
        }

        GetUpdatedEntitiesResponse getResponse = new GetUpdatedEntitiesResponse();
        getResponse.SynchOperation = mySynchs;
        return getResponse;
    }











    /****************** ACK GET UPDATED ENTITIES ************************/
    // Classes that define incoming bits
    global class AckOperation {
        webservice String synchID;
        webservice String entityType;
        webservice Boolean operationValue;
    }
    
    // Classes that define outgoing bits
    global class AckOperationResponse {
        webservice List<AckOperationResult> ackOperationResult;
    }
    global class AckOperationResult {
        webservice String synchID;
        webservice String entityType;
        webservice String errorCode;
    }
    
    webservice static AckOperationResponse AckGetUpdatedEntities(List<AckOperation> ackOperations) {

        // Test code
        List<AckOperationResult> resultList = new List<AckOperationResult>();
        
        for (Integer i=0; i<ackOperations.size(); i++) {
            AckOperationResult a = new AckOperationResult();
            a.synchID = ackOperations[i].synchID;
            a.entityType = ackOperations[i].entityType;
            a.errorCode = '0';
            resultList.add(a);
        }
        
        AckOperationResponse ackResponse = new AckOperationResponse();
        ackResponse.ackOperationResult = resultList;
        return ackResponse;
    }

















    /****************** UPDATE ENTITIES ************************/
    // Classes that define incoming bits
    global class UpdateSynchOperation {
        webservice String synchID;
        webservice String entityType;
        webservice Datetime updateTS;
        webservice String operation;
        webservice UpdateEntity entity;
    }
    
    global class UpdateEntity {
        webservice String integrationID;
        webservice Date synchTS;
        
        // Contact (Artist) fields
        webservice String mobilePhone;
        webservice String email;
        webservice String secondaryEmail;
        webservice String website;
        webservice String businessAddress;
        webservice String businessCity;
        webservice String businessState;
        webservice String businessCountry;
        webservice String businessZipCode;
        
        // Placement (Assignment) fields
        webservice String performingStatus;
        
    }
    
    // Classes that define outgoing bits
    global class UpdateEntitiesResponse {
        webservice List<SynchOperationResult> synchOperationResult;
    }
    
    global class SynchOperationResult {
        webservice String errorCode;
        webservice String errorMessage;
        webservice String synchID;
        webservice String entityType;
    }
    
    
    webservice static UpdateEntitiesResponse UpdateEntities(List<UpdateSynchOperation> synchOperations) {

        // Test code...
        List<SynchOperationResult> responseList = new List<SynchOperationResult>();

        for (UpdateSynchOperation so:synchOperations) {
            // Do updates with the SO data
            SynchOperationResult temp = new SynchOperationResult();
            temp.errorCode = '0';
            temp.synchID = so.synchID;
            temp.entityType = so.entityType;
            responseList.add(temp);
        }
        
        UpdateEntitiesResponse upResponse = new UpdateEntitiesResponse();
        upResponse.synchOperationResult = responseList; 
        return upResponse;
    }
}

 

SScholtzSScholtz

Anybody have any ideas?

 

I think SF just doesn't support inheritance via SOAP WSDLs.  I've done some Googling around, and I've seen posts from other people who have had problems going the other direction, using WSDL to Apex.  WSDLs that have inheritance features in them don't seem to be parsed correctly, and details around child elements/objects don't make it into the class.

 

http://boards.developerforce.com/t5/Apex-Code-Development/Generate-apex-code-from-WSDL-inheritance-problem/td-p/233361

http://forums.sforce.com/t5/forums/forumtopicprintpage/board-id/apex/message-id/33241/print-single-message/false/page/1

 

If inheritance doesn't work going from WSDL to Apex, then it would be consistent if inheritance wasn't supported going from Apex to WSDL.

SScholtzSScholtz

I got an official response from Sales Force developer support, SalesForce currently does not support any kind of SOAP inheritance.

 

Created an Idea for this, vote if you'd like to see it added: https://sites.secure.force.com/success/ideaView?id=08730000000bYanAAE

This was selected as the best answer