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 ....

5
  • 1
    What is the failing JSON string?
    – David Reed
    Apr 1, 2018 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, 2018 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, 2018 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, 2018 at 0:06
  • I did change the name of the class but still its the same issue.
    – Quddus
    Apr 2, 2018 at 0:12

1 Answer 1

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);
4
  • 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, 2018 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, 2018 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/… Apr 3, 2018 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, 2018 at 18:30

You must log in to answer this question.

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