1

Wrapper Class:

global class ApexDataContainer {
        @AuraEnabled
        public List<Purposes>purposes {get;set;}
        public class Purposes{
            @AuraEnabled
            public string purpose {get;set;}
            @AuraEnabled
            public string legalGround {get;set;}
            @AuraEnabled
            public string status {get;set;}
            @AuraEnabled
            public List<Description> description {get;set;}
            @AuraEnabled
            public string version {get;set;}
            @AuraEnabled
            public List<DataIds> dataIds {get;set;}
        }

        public class Description {
            @AuraEnabled
            public string language {get;set;}
            @AuraEnabled
            public string text {get;set;}
        }

        public class DataIds {
        }

    }

Callout Class:

public class CallDevam2 {
        //Wrapper
        public class deserializeResponse
        {
            public String id;
            public String access_token;
        }
        public CallDevam2(){
            ApexDataContainer c1 = new ApexDataContainer();
            ApexDataContainer.Purposes p1 = new ApexDataContainer.Purposes();
            ApexDataContainer.Description d1 = new ApexDataContainer.Description();
            ApexDataContainer.DataIds dIds = new ApexDataContainer.DataIds();       
            List<ApexDataContainer.Purposes> addtolist = new List<ApexDataContainer.Purposes>();
            List<ApexDataContainer.Description> addtodesc = new List<ApexDataContainer.Description>();
            List<ApexDataContainer.DataIds> addtodIds = new List<ApexDataContainer.DataIds>();
            p1.legalGround = 'MyGround';
            p1.purpose = 'purpose';
            p1.status = 'status';
            p1.version = 'version';
            addtolist.add(p1);
            d1.language = 'language';
            d1.text = 'text';
            addtodesc.add(d1);
            p1.description = addtodesc;
            p1.dataIds = addtodIds;
            c1.purposes = addtolist;
            String jsonstr = JSON.serialize(c1);
            **system.debug('@@@'+jsonstr);**

            http http1 = new Http();
            HttpRequest req1 = new HttpRequest();
            req1.setEndpoint('https://test.salesforce.com/services/apexrest/restrequest/');
            req1.setHeader('Authorization','Bearer ' + token1); //The token which i had already recieved used here
            req1.setHeader('Content-Type','application/json');
            req1.setHeader('Accept','application/json');
            req1.setHeader('Content-length',string.valueOf(jsonstr.length()));
            req1.setMethod('POST');
            req1.setBody(jsonstr);
            HttpResponse response1 = http1.send(req1);
            system.debug('response1:'+response1.getBody());

        }
    }

I have seen in the debug log before making a call out that we have the valid json but once it hits the service I get the response as

00:41:07:354 USER_DEBUG [51]|DEBUG|response1:[{"message":"Unexpected parameter encountered during deserialization: purposes at [line:1, column:14]","errorCode":"JSON_PARSER_ERROR"}]

With the same json string if I do within classes, it gets successfully parsed, do we need to do anything extra in REST call out while sending Json request as string.

The exposed service class:

@RestResource(urlMapping='/restrequest/*')
global class RESTservice {
    @HttpPost
    global static String resultsDisplay(String c1){
        try{
        system.debug('1111'+c1);
        ApexDataContainer resp2 = (ApexDataContainer)JSON.deserialize(c1, ApexDataContainer.class);
        system.debug('2222'+resp2);
        return 'Connection established';
        }catch(exception e){
        system.debug('$$$$'+e.getMessage());
        return 'Connection Error';
        }
    }    
}

The ApexDataContainer class is excatly same in both the environments. The request gets failed in the method invoke .

Any ideas , pls ....

  • 1
    What is the failing JSON string? – David Reed Apr 1 '18 at 23:44
  • This is the JSON debug from the above code: USER_DEBUG [28]|DEBUG|@@@{"purposes":[{"version":"version","status":"status","purpose":"purpose","legalGround":"MyGround","description":[{"text":"text","language":"language"}],"dataIds":[]}]} – Quddus Apr 1 '18 at 23:49
  • Error message: 00:41:07:354 USER_DEBUG [51]|DEBUG|response1:[{"message":"Unexpected parameter encountered during deserialization: purposes at [line:1, column:14]","errorCode":"JSON_PARSER_ERROR"}] – Quddus Apr 1 '18 at 23:50
  • I suspect, although I don't have a detailed explanation based on the internals of the JSON parser, that this is a namespace collision between the instance variable ApexDataContainer.purposes and the inner class ApexDataContainer.Purposes. – David Reed Apr 2 '18 at 0:06
  • I did change the name of the class but still its the same issue. – Quddus Apr 2 '18 at 0:12
2

Salesforce handles parameters to a rest service in a slightly funny way.

I'm pretty sure that your parameter is coming through like this:

{
  "c1": {
    "purposes": [
      {
        "version": "version",
        "status": "status",
        "purpose": "purpose",
        "legalGround": "MyGround",
        "description": [
          {
            "text": "text",
            "language": "language"
          }
        ],
        "dataIds": []
      }
    ]
  }
}

ie, c1 is treated as a JSON attribute. So to get the rest of the object, you'd need to deserializeUntyped, grab purposes, stringify and finally deserialize.

Otherwise, you can skip the method param and use this technique:

String r = RestContext.request.requestBody.toString();
AuraDataContainer adc = (AuraDataContainer)JSON.deserialize(r, AuraDataContainer.class);
  • Yes, after lot of research I had used the Restcontext part yesterday because there the request body comes properly. But I am curious to know one thing as you explaned above that the entire body comes under c1, while sending the request body , I am doing.setbody which is a string and in the HTTPPOST method declartion global static String resultsDisplay(String c1) , this is also string. so why the parsing happening on the method call itself. String to String it sould not parse anything ? – Quddus Apr 2 '18 at 10:57
  • Even If i tried with this method structure it failed, @HttpPost global static String resultsDisplay(String c1){ try{ system.debug('1111'+c1); return 'Connection established'; }catch(exception e){ system.debug('$$$$'+e.getMessage()); return 'Connection Error'; } – Quddus Apr 2 '18 at 11:06
  • Remove the param. If there is a param, the requestbody will be null. Source: developer.salesforce.com/docs/atlas.en-us.apexcode.meta/… – Caspar Harmer Apr 3 '18 at 2:46
  • Yeah I got that concept of restcontext, I saw just curious why it was failing for normal param where as I saw sending the body as string ...Anyway its ok as long as we have workarounds. Thanks for our help. – Quddus Apr 3 '18 at 18:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.