12

I get back JSON like the following:

         {
         Id = a0Ef0000002TPKVEA4;
         Name = a0Ef0000002TPKV;
         attributes =             {
             type = "Market__c";
             url = "/services/data/v29.0/sobjects/Market__c/a0Ef0000002TPKVEA4";
         };

The attributes portion doubles the data size. I've searched the docs but can't find a way to remove it. Here is the code I am using

 @HttpGet
 global static Aggregate doGet() {
     RestRequest req = RestContext.request;
     string userid = req.params.get('UserId');

     try {
         User user = [SELECT FirstName, LastName, Title, Email, Phone, MobilePhone,
          Street, City, State, PostalCode, Country, LevelOfCare__c, Username, PERNER__c
          FROM User WHERE Id = :userid];

          List<Market__c> markets = [SELECT Id, Name FROM Market__c];

         return new Aggregate(user, markets);         
     }
     catch (exception e) {
         return null;
     }
 }

 global class Aggregate {
     public User user {get; set;}
     public List<Market__c> markets {get; set;}

     public Aggregate(User u, List<Market__c> m) {
         user = u;
         markets = m;
     }
 } }

4 Answers 4

8

As it is custom Apex code, instead of directly returning the SObject, return a simple "bean" class that just has an Id and Name property with the values copied from the SObject:

public class Bean {
    public Id Id;
    public String Name;
    Bean(SObject sob) {
       this.Id = sob.Id;
       this.Name = (String) sob.get('Name');
    }
}

PS

Based on the posted code, it is the nested SObjects that you need to eliminate:

global class Aggregate {

    public Bean user {get; set;}
    public List<Bean> markets {get; set;}

    public Aggregate(User u, List<Market__c> ms) {
        user = new Bean(u);
        markets = new List<Bean>();
        for (Market__c m : ms) {
            markets.add(new Bean(m));
        }
    }
}
6
  • Thanks, but I thought I was. I've edited my question to include the code I am using. Commented Apr 25, 2014 at 14:49
  • 1
    What happens if you have 100+ fields? This method is not going to be elegant. Any thoughts on alternative, more dynamic way of achieving this? Commented Sep 11, 2014 at 7:41
  • 2
    @Bachovski You can JSON.serialize a Map<String, Object> so I assume (but don't know) that building such a map using describe information will work.
    – Keith C
    Commented Sep 11, 2014 at 7:55
  • I don't think that'll work because when you put your sObject as a value, it still has the attributes in it... I think @executeanon's anwer will do the trick Commented Sep 11, 2014 at 23:51
  • @Bachovski You would replace every SObject with a map, the parent one, the child ones, the grand-child ones and so on.
    – Keith C
    Commented Sep 12, 2014 at 7:56
13

It's a bit hacky, but you could remove the attributes by serialising and deserialising the SObjects to Maps, like this example:

Account acc = [Select Id, Name, (Select Id, Name From Contacts) From Account LIMIT 1];
Map<String,Object> accMap = (Map<String,Object>)JSON.deserializeUntyped(JSON.serialize(acc));

removeAttributes(accMap);

System.debug(JSON.serializePretty(accMap)); // et voila, no attributes

private void removeAttributes(Map<String,Object> jsonObj)  {
    for(String key : jsonObj.keySet()) {
        if(key == 'attributes') {
            jsonObj.remove(key);
        } else {
            if(jsonObj.get(key) instanceof Map<String,Object>) {
                removeAttributes((Map<String,Object>)jsonObj.get(key));
            }
            if(jsonObj.get(key) instanceof List<Object>) {
                for(Object listItem : (List<Object>)jsonObj.get(key)) {
                    if(listItem instanceof Map<String,Object>)  {
                        removeAttributes((Map<String,Object>)listItem);
                    }
                }
            }
        }
    }  
}

Probably not any more palatable that @KeithC's answer, but an alternative.

2
  • 2
    I've used this type of pattern before, and it's the best thing available right now if you need to be at all dynamic. Commented Sep 11, 2014 at 19:33
  • 1
    Has anyone done any Apex performance testing on this approach? We are considering this approach for situations where we're doing anything from 20-50 SOQL queries returning lots of results, as well as metadata for particular objects, so we don't want to make the Apex processing portion take any longer than necessary --- any idea how long a serialize/deserialize pair takes on a massive List<SObject>?
    – zachelrath
    Commented Jan 20, 2015 at 12:35
1

You can simply use JSONGenerator to get rid of the "attributes" element.

Refer to this link: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_json_jsongenerator.htm

-1

Convert the object into a string and do not use standard salesforce serialize method.

Ex:

Account a = new Account(); String resString = String.valueof(a); return resString;

In this way we could not have \ in the response.

You must log in to answer this question.

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