0

I have created a wrapper class to create an Object and send it as a request to a third party system. It was working well. But after I added a two new arguments of the Datatype Date, I am getting the below error.

Constructor not defined: [SFDC_DataObject.CustomerAccountObject].<Constructor>(Id, String, Id, String, Id, String, Integer, NULL, String, String, Id, String, NULL, String, String, String, String)

The request that I am creating and sending is as below.

SFDC_DataObject.CustomerAccountObject cusAccObj = new SFDC_DataObject.CustomerAccountObject(o.AccountId, o.Customer_Name__c, o.Agency_Name__r.Id,o.Agency_Name_OB__c, o.Opportunity.OwnerId, o.Opportunity.Owner.FederationIdentifier, PrimarySalesSplitPercent, null, secSOSalesforceId.get(o.OpportunityId), secSOSalesforceEmail.get(o.OpportunityId), o.Opportunity.Customer_Success_Manage__r.Id, o.Opportunity.Customer_Success_Manage__r.FederationIdentifier, null, o.Billing_Email__c, o.Billing_Phone__c, o.Bill_To_Name__c, o.Billing_Notes__c);

My wrapper class for the same object is as below.

public class CustomerAccountObject {
        public String  sfCustomerId;
        public String  customerName;
        public String  sfAgencyId;
        public String  agencyName;
        public String  sfPrimarySalesOwnerId;
        public String  primarySalesOwnerEmail;
        public Integer primarySalesOwnerPercentage;
        public Date    primarySalesOwnerEffectiveFrom;
        public String  sfSecondarySalesOwnerId;
        public String  secondarySalesOwnerEmail;
        public Date    secondarySalesOwnerEffectiveFrom;
        public String  sfAccountManagerId;
        public String  accountManagerEmail;
        public String  billingEmail;
        public String  billingPhone;
        public String  billingName;
        public String  billingNotes;

        public CustomerAccountObject() {}

        public CustomerAccountObject(String sfCustomerId, String customerName, String sfAgencyId, String agencyName, String sfPrimarySalesOwnerId, String primarySalesOwnerEmail, Integer primarySalesOwnerPercentage, Date primarySalesOwnerEffectiveFrom, String sfSecondarySalesOwnerId, String secondarySalesOwnerEmail, Date secondarySalesOwnerEffectiveFrom, String sfAccountManagerId, String accountManagerEmail, String billingEmail, String billingPhone, String billingName, String billingNotes) {
            this.sfCustomerId                     = sfCustomerId;
            this.customerName                     = customerName;
            this.sfAgencyId                       = sfAgencyId;
            this.agencyName                       = agencyName;
            this.sfPrimarySalesOwnerId            = sfPrimarySalesOwnerId;
            this.primarySalesOwnerEmail           = primarySalesOwnerEmail;
            this.primarySalesOwnerPercentage      = primarySalesOwnerPercentage;
            this.primarySalesOwnerEffectiveFrom   = primarySalesOwnerEffectiveFrom;
            this.sfSecondarySalesOwnerId          = sfSecondarySalesOwnerId;
            this.secondarySalesOwnerEmail         = secondarySalesOwnerEmail;
            this.secondarySalesOwnerEffectiveFrom = secondarySalesOwnerEffectiveFrom;
            this.sfAccountManagerId               = sfAccountManagerId;
            this.accountManagerEmail              = accountManagerEmail;
            this.billingEmail                     = billingEmail;
            this.billingPhone                     = billingPhone;
            this.billingName                      = billingName;
            this.billingNotes                     = billingNotes;
        }
    }

I began getting the error after I added the null for the Date arguments I.e primarySalesOwnerEffectiveFrom and secondarySalesOwnerEffectiveFrom during the Object creation.

Can anyone please let me know what am I doing wrong here.

Akshay Vasu
  • 445
  • 1
  • 12
  • 33

1 Answers1

1

The order is wrong.

In c-tor definition you have

String sfCustomerId, String customerName, String sfAgencyId, String agencyName, String sfPrimarySalesOwnerId, String primarySalesOwnerEmail, Integer primarySalesOwnerPercentage, Date primarySalesOwnerEffectiveFrom, String sfSecondarySalesOwnerId, String secondarySalesOwnerEmail, Date secondarySalesOwnerEffectiveFrom + 6 more Strings

So

... Integer, Date, String, String, Date, ...

But the code that calls it goes

o.AccountId, o.Customer_Name__c, o.Agency_Name__r.Id,o.Agency_Name_OB__c, o.Opportunity.OwnerId, o.Opportunity.Owner.FederationIdentifier, PrimarySalesSplitPercent, null, secSOSalesforceId.get(o.OpportunityId), secSOSalesforceEmail.get(o.OpportunityId), o.Opportunity.Customer_Success_Manage__r.Id, o.Opportunity.Customer_Success_Manage__r.FederationIdentifier, null, + 4 strings

There are extra 2 strings before 2nd null. And only 4 strings after it. You need to inject that null just after secSOSalesforceEmail?

This will get only worse to maintain as time goes on. Consider making a simple constructor and making the properties public. You could then set them after constructor in normal call. And if you don't need dates you just don't write line that sets date fields instead of injecting null at right position.

Follow-up edit

Not sure if there's an official guide to that technique or a blog post. Tools like Apex-PMD complain when you make methods with too many arguments, rules like "Avoid long parameter lists".

One way would be to do something like this:

SFDC_DataObject.CustomerAccountObject cusAccObj = new SFDC_DataObject.CustomerAccountObject();
cusAccObj.sfCustomerId                      = o.AccountId;
cusAccObj.customerName                      = o.Customer_Name__c;
cusAccObj.sfAgencyId                        = o.Agency_Name__c;
cusAccObj.agencyName                        = o.Agency_Name_OB__c;
cusAccObj.sfPrimarySalesOwnerId             = o.Opportunity.OwnerId;
cusAccObj.primarySalesOwnerEmail            = o.Opportunity.Owner?.FederationIdentifier;
cusAccObj.primarySalesOwnerPercentage       = PrimarySalesSplitPercent;
// cusAccObj.primarySalesOwnerEffectiveFrom = null; // just don't bother with the line?
cusAccObj.sfSecondarySalesOwnerId           = secSOSalesforceId.get(o.OpportunityId);
// ..

That's not very object oriented, not very elegant but caller has full control on the mapping. Problem will be if you need to map new field and this has been copy-pasted into 10 places. You'll have to update them all (which will be easier than adding N-th parameter to long call but still)

Another way would be to create a baseline constructor that takes whole Order object (it's an Order, right?), it'd map the fields internally. Then if needed - you specify some extra fields after constructor. Or maybe make few constructors?

public CustomerAccountObject(){
    // I'm parameterless, I'm doing nothing! I'm just here if somebody needs a really custom field mapping or JSON deserialisations need a parameterless one
}
public CustomerAccountObject(Order o){
    // I can map all fields from Order! Want to map new field? Just chuck it in here!
    sfCustomerId = o.AccountId;
    // ...
}
public CustomerAccountObject(Order o, Map<Id, String> secSOSalesforceId, Map<Id, String> secSOSalesforceEmail){
    // I can do everything above and few more fields too!
    this(o);
    sfSecondarySalesOwnerId = secSOSalesforceId.get(o.OpportunityId);
    secondarySalesOwnerEmail = secSOSalesforceEmail.get(o.OpportunityId);
}

You have bit of code reuse, the Order fields mapping is defined in just 1 place, just 1 line to change in future. You don't have an orgy of this everywhere anymore. And then your call if you really need the last constructor or you'll call the one that just takes Order o and then set the 2 extra fields after it finishes.

eyescream
  • 18,088
  • 2
  • 34
  • 46
  • *facepalm* Thank you. I didn't notice it. Can you please provide me any reference such as a blog link or another answer in which the constructor has been defined the way you have mentioned above. So that I can work on my code based on those examples? – Akshay Vasu Nov 23 '20 at 09:03
  • Better? I don't know if there's an official name for this "design pattern" or something. It just looks cleaner to pass whole objects around, not decompose them to their single field properties. Object-oriented programming? :D – eyescream Nov 23 '20 at 10:04