0

I have been trying to achieve a JSON structure that looks very similar to this

{
  "firstName": "uhfas",
  "lastName": "kkkjfi",
  "status": "9jiak",
  "address": {
      "street": "eerwrff",
      "city": "eaetsty"
      ...
  }
}

I played around a bit with maps but I feel like I am making it more complicated than what it actually is.

Map<String, Map<String, String>> finalMap = new Map<String, Map<String, String>>();
Map<String, String> accMap = new Map<String, String>();
Map<String, String> addressMap = new Map<String, String>();
for(Account acc: accounts){
   accMap.put('firstName', acc.FirstName);
   accMap.put('lastName', acc.LastName);
   accMap.put('status', acc.Status__c);
   addressMap.put('street', acc.Address__r.Street__c);
   addressMap.put('city', acc.Address__r.City__c);
   ....
   
   finalMap.put('address', addressMap);
   finalMap.put('account', accMap);
}

System.debug('JSON: ' + JSON.serialize(finalMap));

Okay so this almost gives me the desired result but the acc data has a key basically since I made it a map. It has to be the same kind of map like the addressMap though. I am probably missing a very simple alternative rn.

Thank you in advance!

{
  "account":{
      "firstName": "uhfas",
      "lastName": "kkkjfi",
      "status": "9jiak"
  },
  "address": {
      "street": "eerwrff",
      "city": "eaetsty"
      ...
  }
}
0

Yes, you are right, you do not have to use this strict approach with setting all structure to the root, you can use Object in Map value. You also have List of Accounts, so you need to serialize it as List, too.

List<Object> accountsList = new List<Object>();

for (Account acc : accounts) {
    accountsList.add(new Map<String, Object>{
            'address' => new Map<String, Object>{
                    'street' => acc.Address__r.Street__c, 
                    'city' => acc.Address__r.City__c
            },
            'firstName' => acc.FirstName,
            'lastName' => acc.LastName,
            'status' => acc.Status__c
    });
}

System.debug('JSON: ' + JSON.serialize(accountsList));
0
1

A map has unique keys. In the last 2 lines of for loop as you are putting same keys address and account, the old data will get overwritten. It would work if you are sure that there will be only one record in accounts list.

The simplest alternative that I follow is usually create an Apex class using tools available online if the JSON structure is not dynamic (fields can be empty, that is not dynamic). This gives type safety and ensures that names are correct. Once the data is added to class, serialize and get the JSON.

There are some downsides as well especially regarding reserved keywords.

The below class would generate an array as

[
    {
        "firstName": "uhfas",
        "lastName": "kkkjfi",
        "status": "9jiak",
        "address": {
            "street": "eerwrff",
            "city": "eaetsty"
        }
    },
    {
        "firstName": "uhfas",
        "lastName": "kkkjfi",
        "status": "9jiak",
        "address": {
            "street": "eerwrff",
            "city": "eaetsty"
        }
    }
]

Class details

public with sharing class JsonGeneratorClass {

    public String generateJSON() {
        List<JsonGeneratorClass.Body> result = new List<JsonGeneratorClass.Body>();
        for (User u : [SELECT FirstName, LastName, AddressStreet__c, AddressCity__c FROM User LIMIT 10]) {
            Body userBody = new Body();
            userBody.firstName = u.FirstName;
            userBody.lastName = u.LastName;
            userBody.status = 'Active';
            userBody.address.street = u.AddressStreet__c;
            userBody.address.city = u.AddressCity__c;
            result.add(userBody);
        }
        return JSON.serialize(result, true);
    }

    public class Body {
        public String firstName;    //uhfas
        public String lastName;    //kkkjfi
        public String status;    //9jiak
        public AddressClass address;

        public Body() {
            this.address = new AddressClass();
        }
    }
    class AddressClass {
        public String street;    //eerwrff
        public String city;    //eaetsty
    }
}
5
  • Looks nice and clean. What happens if I want to display even the values that are empty (null in that case)? – devoid_of_chill May 30 at 15:42
  • You can call the method JSON.serialize(result); or JSON.serialize(result, false); – manjit5190 May 30 at 18:59
  • Oh I did not know it takes a second parameter Ijust realized you had it set like that. Could not find documentation either but I only did a basic search! Thanks a lot Imma try removing it now. – devoid_of_chill May 31 at 6:32
  • This case should be used only when we don't want to exclude any keys upon condition, correct? Since they all get initialized when the constructor is called. – devoid_of_chill May 31 at 9:57
  • Passing the second parameter as false serializes all parameters, even null ones. Passing it as true suppresses nulls. – manjit5190 May 31 at 11:05
0

You need to put the addressMap into the accMap like this:

accMap.put('address', addressMap);

0

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.