5

My client wants to send Account and Contact information from external system. For that reason, I have created one custom webservice class which can take any kind of data and based on the structure of data, I want to call respective classes.

IRequestInfo

global abstract class IRequestInfo {
}

IResponseInfo

global abstract class IResponseInfo {
    webservice String result {get;set;}
}

There are AccountRequestInfo and ContactRequestInfo global classes which are extended from IResponseInfo and those hold respective attributes like name, phone etc.

global class AccountRequestInfo extends IRequestInfo{
    webservice String name {get;set;}
    webservice String extenalId {get;set;}
}

My Main entry point webservice class

global class CustomWebserviceFacade {

    webservice static List<IResponseInfo> process(List<IRequestInfo> dataMap){

        if(dataMap instanceof List<AccountRequestInfo>)
        {
            System.debug('for Account related data parse request');
            List<IResponseInfo> returnInfo = CustomAccountService.processData(dataMap);
            return returnInfo;
        }
        else if(dataMap instanceof List<ContactRequestInfo>)
        {
            System.debug('for Contact related data parse request');
            List<IResponseInfo> returnInfo = CustomContactService.processData(dataMap);
            return returnInfo;
        }
        return null;
    }
}

Issue I am facing is, when I generate WSDL and try to send parameters to the process method of type AccountRequestInfo or ContactRequestInfo, those are not recognizable. Since those info classes are not in my main webservice class, though those are global classes.

So, how I can distribute the classes to external system so that all my relevant info classes can be recognized.

Is that Info classes should exist in the main webservice class? If so, it might defeat the design.

If I write test class and call the process method internally, it works absolutely fine.

Please suggest.

7
  • As far as I can tell you, you will need to have the implementation classes AccountRequestInfo and ContactRequestInfo defined right within your web service class. WSDL as a document should contain the definition of the data types which any external client will utilize as a contract to invoke the web services exposed. If the generated WSDL doesn't have the definition for the data type that can be used, the client won't be able to construct it then.
    – Jayant Das
    May 10, 2019 at 14:24
  • I would suggest using the FuseIT SFDC Explorer to import the WSDL to your org and generate the apex class. fuseit.com/products/fuseit-sfdc-explorer/…. It is very easy to use. May 10, 2019 at 15:05
  • @jayantdas I am looking for a pattern to use the concepts without putting all info classes in main webservice class, Rather than Account, Contact there are other 3 types of objects data to be received into Salesforce. If I put all types of info in the same class then design will not be good. May 10, 2019 at 15:23
  • @SantanuBoral I understand, but unfortunately if you use SOAP WS, you would need to define those data types in the WSDL which won't happen in this case. Is SOAP the only option here? Can't you utilize REST as a fallback?
    – Jayant Das
    May 10, 2019 at 15:25
  • 2
    FYI your naming is somewhat misleading as the industry convention in all my stops so far has been that IFoo, IBar, etc are interfaces. For abstract classes we typically drop the prefix.
    – Adrian Larson
    May 10, 2019 at 19:50

1 Answer 1

2

Since SOAP WSDL is strongly typed language so, defining superclass as an argument and passing the subclass value will not work here.

The following design has multiple benefits:

  • There is only one single entry point for multiple objects data insert. Today, we have Accounts and Contacts data to be inserted and in coming sprints it will allow other financial data for other objects.

  • I don't have to create many custom webservice classes to send to my client to prepare stub.

  • There will be no change in method signature of process().

  • Since all those info classes are declared global and here I am taking reference of those info classes, so changing those info classes' properties, I dont need to generate WSDL again. My code is easier to maintain.

  • Facade design pattern works well in this implementation.

Here is the way I have proceed.

Created Wrapper class which will hold all the instances of Info classes. Now pass that Wrapper class as a parameter in the process method.

Based on the size of List it will go CustomAccountService or CustomContactService.

global class CustomWebserviceFacade {
    
    global class Wrapper{
        webservice List<AccountRequestInfo> accountInfo;
        webservice List<ContactRequestInfo> contactInfo;
    }
    
    webservice static List<IResponseInfo> process(Wrapper dataMap){
       
        System.debug('inside facade');
        
        if(dataMap.accountInfo !=null && dataMap.accountInfo.size()>0)
        {
            System.debug('inside facade AccountRequestInfo');
            List<IResponseInfo> returnInfo = CustomAccountService.processData(dataMap.accountInfo);
            return returnInfo;
        }
        else if(dataMap.contactInfo !=null && dataMap.contactInfo.size()>0)
        {
            System.debug('inside facade ContactRequestInfo');
            List<IResponseInfo> returnInfo = CustomContactService.processData(dataMap.contactInfo);
            return returnInfo;
        }
        return null;
    }
}

Since, those info classes are global, so those structures are available to provide inputs. As, external system will send one type of data at a time thats why I have put if-else logic.

soapui

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .