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
ForceRookieForceRookie 

How to solve error: Future methods do not support parameter type of List<>?

I have created a trigger callout but I am getting this error..

Please help me get through..

Handler:

public class FileDeleteHandler {
    @future(callout=true)
    public void fileDeleteMethod(List<ContentDocument> scope) {
        List<CustomSettings__c> settings =  [SELECT BucketName__c, ClientKey__c, Region__c, SecretKey__c FROM CustomSettings__c LIMIT 1];

        String bucketName = '';
        String region = '';
        String clientKey = '';
        String secretKey = '';

        if(!settings.isEmpty()){
            bucketName = settings[0].BucketName__c;
            region = settings[0].Region__c;
            clientKey = settings[0].ClientKey__c;
            secretKey = settings[0].SecretKey__c;
            if(String.isBlank(bucketName)||String.isBlank(region)||
                String.isBlank(clientKey)||String.isBlank(secretKey)){
                return;
            }
        }
        Set<Id> fileIds = new Set<Id>();
        for (ContentDocument cv : scope) {
            fileIds.add(cv.Id);
        }

        List<Custom_Object__c> coList = [SELECT Id, Name, Path__c, File_ID__c, File_Saved__c FROM Custom_Object__c WHERE File_ID__c =: fileIds];

        if (!coList.isEmpty()) {
            if (coList[0].File_Saved__c== true) {
                //make callout
                //delete file from AWS
                List<ContentVersion> cvs = [SELECT Title, ContentDocumentId, FileExtension, FileType, VersionData FROM ContentVersion WHERE ContentDocumentId IN :fileIds];

                String path = coList[0].Path__c; //Salesforce/ObjectName/RecordId/Filename

                String formattedDateString = Datetime.now().format('EEE, dd MMM yyyy HH:mm:ss z');
                Blob data = cvs[0].VersionData; // System.ListException: List index out of bounds: 0

                HttpRequest req = new HttpRequest();
                Http http = new Http();

                req.setHeader('Content-Type', cvs[0].FileExtension);
                req.setMethod('DELETE');
                req.setHeader('Host','s3.amazonaws.com');
                req.setEndpoint('https://s3.amazonaws.com'+'/'+bucketName+'/'+path);
                req.setHeader('Date',formattedDateString);
                req.setHeader('Authorization', createAuthHeader('DELETE', cvs[0].FileExtension, path, formattedDateString, bucketName, clientKey, secretKey));
                req.setBodyAsBlob(data);
                req.setHeader('Content-Length', String.valueOf((EncodingUtil.base64Encode(data)).length()));

                try{
                    HTTPResponse res = http.send(req);

                    System.debug('MYDEBUG: ' + cvs[0].Title + ' RESPONSE STRING: ' + res.toString());
                    System.debug('MYDEBUG: ' + cvs[0].Title + ' RESPONSE STATUS: '+res.getStatus());
                    System.debug('MYDEBUG: ' + cvs[0].Title + ' STATUS_CODE:'+res.getStatusCode());

                } catch(System.CalloutException e) {
                    System.debug('AWS Callout Exception on ' + cvs[0].Title + 'ERROR: ' + e.getMessage());
                }
            } else if (coList[0].File_Saved__c== false) {
                 delete coList;
            }
        }
    }

    public string createAuthHeader(String method,String contentType,String filename,String formattedDateString,String bucket,String client,String secret){
        string auth;
        String stringToSign = method+'\n\n'+contentType+'\n'+formattedDateString+'\n/'+bucket+'/'+filename;
        Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(secret));
        String sig = EncodingUtil.base64Encode(mac);
        auth = 'AWS' + ' ' + client + ':' + sig;
        return auth;
    }
}


Trigger:

trigger DocumentTrigger on ContentDocument (before delete) {
    if (Trigger.isBefore) {
        if (Trigger.isDelete) {
            FileDeleteHandler handler = new FileDeleteHandler();
            handler.fileDeleteMethod(Trigger.old);
        }
    }
}
Ajay K DubediAjay K Dubedi
Hi,
Methods with the future annotation must be static methods, and can only return a void type. The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types. Methods with the future annotation cannot take sObjects or objects as arguments.

The reason why sObjects can’t be passed as arguments to future methods is because the sObject might change between the time you call the method and the time it executes. In this case, the future method will get the old sObject values and might overwrite them. To work with sObjects that already exist in the database, 
pass the sObject ID instead (or collection of IDs) and use the ID to perform a query for the most up-to-date record.
-Methods with the future annotation must be static methods.
-Can only return a void type.
-The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types.
-Methods with the future annotation cannot take sObjects or objects as arguments.

So I would suggest passing a Set<ID> & requerying for the sObject records in your @future method.

I hope you find the above solution helpful. If it does, please mark as Best Answer to help others too.
Thanks,
Ajay Dubedi
ForceRookieForceRookie

Hi Ajay, can you provide an example of this "So I would suggest passing a Set<ID> & requerying for the sObject records in your @future method."?

I tried Set but it's not working for me.

ForceRookieForceRookie

Error: List index out of bounds: 0

Handler:

public class FileDeleteHandler {
    @future(callout=true)
    public static void fileDeleteMethod(Set<Id> fileIds) {
        List<CustomSettings__c> settings =  [SELECT BucketName__c, ClientKey__c, Region__c, SecretKey__c FROM CustomSettings__c LIMIT 1];

        String bucketName = '';
        String region = '';
        String clientKey = '';
        String secretKey = '';

        if(!settings.isEmpty()){
            bucketName = settings[0].BucketName__c;
            region = settings[0].Region__c;
            clientKey = settings[0].ClientKey__c;
            secretKey = settings[0].SecretKey__c;
            if(String.isBlank(bucketName)||String.isBlank(region)||
                String.isBlank(clientKey)||String.isBlank(secretKey)){
                return;
            }
        }

        List<Custom_Object__c> coList = [SELECT Id, Name, Path__c, File_ID__c, File_Saved__c FROM Custom_Object__c WHERE File_ID__c =: fileIds];

        if (!coList.isEmpty()) {
            if (coList[0].File_Saved__c== true) {
                List<ContentVersion> cvs = [SELECT Title, ContentDocumentId, FileExtension, FileType, VersionData FROM ContentVersion WHERE ContentDocumentId IN :fileIds]; //This is EMPTY!

                String path = coList[0].Path__c;

                String formattedDateString = Datetime.now().format('EEE, dd MMM yyyy HH:mm:ss z');
                Blob data = cvs[0].VersionData; // System.ListException: List index out of bounds: 0

                HttpRequest req = new HttpRequest();
                Http http = new Http();

                req.setHeader('Content-Type', cvs[0].FileExtension);
                req.setMethod('DELETE');
                req.setHeader('Host','s3.amazonaws.com');
                req.setEndpoint('https://s3.amazonaws.com'+'/'+bucketName+'/'+path);
                req.setHeader('Date',formattedDateString);
                req.setHeader('Authorization', createAuthHeader('DELETE', cvs[0].FileExtension, path, formattedDateString, bucketName, clientKey, secretKey));
                req.setBodyAsBlob(data);
                req.setHeader('Content-Length', String.valueOf((EncodingUtil.base64Encode(data)).length()));

                try{
                    HTTPResponse res = http.send(req);

                    System.debug('MYDEBUG: ' + cvs[0].Title + ' RESPONSE STRING: ' + res.toString());
                    System.debug('MYDEBUG: ' + cvs[0].Title + ' RESPONSE STATUS: '+res.getStatus());
                    System.debug('MYDEBUG: ' + cvs[0].Title + ' STATUS_CODE:'+res.getStatusCode());

                } catch(System.CalloutException e) {
                    System.debug('AWS Callout Exception on ' + cvs[0].Title + 'ERROR: ' + e.getMessage());
                }
            } else if (coList[0].File_Saved__c== false) {
                 delete coList;
            }
        }
    }

    public static string createAuthHeader(String method,String contentType,String filename,String formattedDateString,String bucket,String client,String secret){
        string auth;
        String stringToSign = method+'\n\n'+contentType+'\n'+formattedDateString+'\n/'+bucket+'/'+filename;
        Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(secret));
        String sig = EncodingUtil.base64Encode(mac);
        auth = 'AWS' + ' ' + client + ':' + sig;
        return auth;
    }
}


Trigger:

trigger DocumentTrigger on ContentDocument (before delete) {
    Set<Id> fileIds = new Set<Id>();
    fileIds = Trigger.oldMap.keySet();
    FileDeleteHandler.fileDeleteMethod(fileIds);
}