Apex Rest JSON serialization Error: Invalid type for Http* method: ….Map.Object

Background

I’m developing some generics apex web service (Rest). The response should be an standardised json schema like this:

{
 "res": true,
 "message": "Records Upserted Ok",
 "data" : {ANYTHING}
}  

Where data attribute could be any result

sample 1 of data:

{
 "success" : [{"salesforceId":"XXXX","externalId":"ZZZZ"}],
 "errors" : [{"externalId":"YYYY","error":"Price field is required"}],
}

sample 2 of data:

{ "queryData": [
   {"id":"XXXXX","name":"Messi"}, 
   {"id":"ZZZZZ","name":"Kun"}
  ]
}

Approach

I’ve created a response helper class like this:

 //abstract basic class  (I have this )
 abstract class JSONResponseBase {

    public Boolean res;
    public String message;    
    // special methods here 

 }  

 global class JSONResponseMap extends JSONResponseBase {

        public Map<String,Object> data;

        public JSONResponseMap(Boolean res, String message, Map<String,Object> data){
            super(res, message);
            this.data = data;
        }
    }

Therefore, my web services have always this code:

@RestResource(urlMapping='/MyWS/*')
global class AccountCustomWS {
    @HttpPost
    global static JSONResponseMap upsertAccount() {

        JSONResponseMap res = new JSONResponseMap();

        // my code here

        return res;
    }

Problem

When I try to save the webservice class I’m getting this compilation error:

Invalid type for Http* method: JSONResponseMap.Map.Object (Line: 5)

I’ve noticed that if I change the data attribute to map<String, String> it works ok

Question

  1. Am I missing something?
  2. Is this a limitation (un-documented) of
    apex rest web service?
  3. What would be the best workaround to
    response a generic data attr?

Answer

First, I don’t know of any explicit documentation about what the framework will accept as serializable signatures. So the answer to your question 2 is I think yes. Certainly SObjects, Lists, Maps and bean-like classes with definite field types work.

This class:

@RestResource(urlMapping='/MyWS/*')
global class AccountCustomWS {

    global interface Anything {
    }

    private class MyAnything implements Anything {
        public String name = 'value';
    }

    @HttpGet
    global static Map<String, Anything> doGet() {
        return new Map<String, Anything>{'any' => new MyAnything()};
    }
}

will compile and produces this JSON:

{"any":{"name":"value"}}

in response to a GET that ends with .json. So it appears that the compiler and runtime can be fooled by using an empty interface in place of Object and this approach may meet your needs and so is a possible answer to your question 3. But how far that can be taken (and how guaranteed the support is over time) is open to question. Generally you are safer following the KISS principle with Apex.

Interestingly, if you ask for XML with the same class (e.g no .json extension) you get this error:

Unsupported return type for XML: MAP<String,AccountCustomWS.Anything>

Attribution
Source : Link , Question Author : Martin Borthiry , Answer Author : Keith C

Leave a Comment