0

When I try to deserialize the JSON response I am getting 'System.JSONException: Malformed JSON: Expected '[' at the beginning of List/Set'

Json Response body is "[{\"ExternalId\":\"345678\"}]". Do any one have any idea where I am making mistake or any modification in code that can fix this out.

Code to handle the response

public class SendFiles {

public List<Attachment> attLst {get;set;}

public SendFiles(){
    attLst = new List<Attachment>();
    attLst = [SELECT Id, Name, body, ParentId FROM Attachment ];
}

public String doAauth2Requset(){        
    //Custom Metadata
    /*Start*/
    String requestUrl = '';// Remote Site settings
    String client_id = '';
    String client_secret = '';
    String username = '';
    String password = ''; //Password with security token
    /*End*/
    
    String Body;
        Body = 'grant_type=password&client_id='+client_id+'&client_secret='+client_secret+'&username='+username+'&password='+password;
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    HttpResponse res=new HttpResponse();
    req.setTimeout(120000);
    req.setEndpoint(requestUrl);
    req.setBody(Body);
    req.setMethod('POST');
    res=h.send(req);
    return res.getBody(); 
}

public class Oauth2Response{
    public String access_token;
}

public void selectedFileForSending(){
    String resposeBody = doAauth2Requset();
    Oauth2Response respose = new Oauth2Response();
    respose = (Oauth2Response) JSON.deserialize(resposeBody, Oauth2Response.Class);
    
    if(attLst.size() > 0){
        Set<String> parentIds = new Set<String>();
        for(Attachment att : attLst){
            parentIds.add(att.parentId);
        }
        Map<String, String> att_ParentExternalId = new Map<String, String> ();
        if(parentIds.size() > 0){
            for(Account acc : [SELECT Id, External_Id__c FROM Account WHERE ID IN : parentIds]){
                att_ParentExternalId.put(acc.Id, acc.External_Id__c);
            }
        }
        if(att_ParentExternalId.values().size() > 0){    
            List<JSONRequest> requestJson = new List<JSONRequest>();            
             for(Attachment att : attLst){
                if(att_ParentExternalId.containsKey(att.parentId)){
                    String encodedBody = EncodingUtil.base64Encode(att.Body);
                    JSONRequest request = new JSONRequest();
                        request.fileUploadName = att.Name;
                        request.fileUploadBody = encodedBody;
                        request.parentId = att_ParentExternalId.get(att.parentId);
                    requestJson.add(request);
                }
            }
            String requestUrl = '';//Custom Metadata and Remote Site settings
            String body =  JSON.serialize(requestJson);
            
            Http h = new Http();
            HttpRequest req = new HttpRequest();
            HttpResponse res=new HttpResponse();
            req.setTimeout(120000);
            req.setEndpoint(requestUrl);
            req.setHeader('Content-Type','application/json');
            req.setHeader('Accept','application/json');
            String val = 'Bearer '+respose.access_token;
            req.setHeader('Authorization',val);
            req.setBody(body);
            req.setMethod('POST');            
            res=h.send(req);
            // Here I am trying to read the response
            String jsonBody = String.valueOf(res.getBody());                 
            system.debug('getBody :: '+jsonBody); // debug "[{\"ExternalId\":\"345678\"}]"
            List<JSONAccount> accountExternalIds = new List<JSONAccount>();
            accountExternalIds = (List<JSONAccount>)JSON.deserialize(jsonBody, List<JSONAccount>.Class);
            system.debug('accountExternalIds :: '+accountExternalIds);
            
            List<Account> acLst = new List<Account>();
            for(JSONAccount aEx : accountExternalIds){
                system.debug('aEx '+ aEx.ExternalId);
                Account ac = new Account(External_Id__c = String.valueof(aEx.ExternalId), IsInserted__c  = true);
                acLst.add(ac);
            }
            system.debug('acLst '+ acLst);
            upsert acLst External_Id__c;    
        }
    }
} 

public class JSONRequest {
    public String fileUploadName;
    public String fileUploadBody;
    public String parentId;
}

/**
*  @description Response JSON
*/
public class JSONAccount {
    public String ExternalId;
}
}

Response send from

   @RestResource(urlMapping='/Attachments/*')
    global with sharing class TransferAttachments {

    @HttpPost
    global static String createAttachments(){
    String requestBody = RestContext.request.requestBody.toString();
    system.debug('requestBody '+ requestBody);
    List<JSONRequest> priceRecs = new List<JSONRequest>();
    priceRecs = (List<JSONRequest>) JSON.deserialize(requestBody, List<JSONRequest>.class);
    
    if(priceRecs.size() > 0){
        Set<String> parentIds = new Set<String>();            
        for(JSONRequest res : priceRecs){
            parentIds.add(res.parentId);
        }
        
        if(parentIds.size() > 0){  
            Map<String, Account> att_ParentExternalId = new Map<String, Account> ();
            Map<String, Account> accountMap = new Map<String, Account> ();
            for(Account acc : [SELECT Id, External_Id__c FROM Account WHERE External_Id__c IN : parentIds]){
                att_ParentExternalId.put(acc.External_Id__c, acc);
                accountMap.put(acc.Id, acc);
            }
            
            List<Attachment> attachments = new List<Attachment>();        
            for(JSONRequest res : priceRecs){
                Attachment att = new Attachment(ParentId = att_ParentExternalId.get(res.parentId).Id, Body = EncodingUtil.base64Decode(res.fileUploadBody), Name = res.fileUploadName);
                attachments.add(att);
            }                
            try{
                List<Database.SaveResult> insertResults = Database.insert (attachments);
                Set<Id> successIds = new Set<Id>();
                for (Database.SaveResult sr : insertResults) {
                    if (sr.isSuccess()) {                           
                        successIds.add(sr.getId());     
                    } 
                }
                Set<String> accountIds = new Set<String>();
                if(successIds.size() > 0){
                    for(Attachment atts: [SELECT ParentId FROM Attachment WHERE Id IN : successIds]){
                        accountIds.add(atts.ParentId);
                    }
                }
                List<JSONAccount> accountIdJS = new List<JSONAccount>();
                if(successIds.size() > 0){                        
                    for(Account acc: [SELECT External_Id__c FROM Account WHERE Id IN : accountIds]){
                        JSONAccount JSacct = new JSONAccount();
                        JSacct.ExternalId = acc.External_Id__c;
                        accountIdJS.add(JSacct);
                    }
                }
                system.debug(JSON.serialize(accountIdJS));
                return JSON.serialize(accountIdJS);// Here from where I generate the response 
            }catch(Exception ex){
                return 'Error : '+ex.getMessage();
            }
        }
    }
    return null;
}

/**
*  @description Read Post request JSON
*/
global class JSONRequest {
    public String fileUploadName;
    public String fileUploadBody;
    public String parentId;
} 

/**
*  @description Response JSON
*/
global class JSONResponse {
    public String parentId;
    public String isSuccess;
}

/**
*  @description Response JSON
*/
global class JSONAccount {
    public String ExternalId;
}

}
2
  • I am guessing it is double serielization. Can you try by returning the accountIdJS directly without serializing in the createAttachment method and change the return type from String to List<JsonAccount>
    – manjit5190
    Commented Sep 27, 2020 at 21:00
  • @manjit5190, Yes you are right. This fix for me but cant understand what is the issue with JSON.deserialize() when it is JSON.serialize().
    – Anu
    Commented Sep 30, 2020 at 15:17

1 Answer 1

0

A workaround that I'm pretty sure is gonna work is to deserialize that "requestBody" using the untype deserialization

List<JSONRequest> priceRecs = new List<JSONRequest>();
List<Object> deserializedRequests = (List<Object>) JSON.deserializeUntyped(requestbody);
For(Object o : deserializedRequests){
        priceRecs.add((JSONRequest) JSON.deserialize(o, JSONRequest.class));
}

The problem with the normal deserialization "might be" related to the fact you are trying to deserialize a list of a custom object (in sense of "being from a class")

You must log in to answer this question.

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