Blog-01-05
Tue Jun 14 2022 15:47:02 GMT+0000 (Coordinated Universal Time)
Saved by @Justus
/** * Example code to show the difference in heapsize for a large payload whilst handling * the result in 2 different ways * !! This is not a production implementation, only as an illustation !! */ // Execute the different methods to see the difference in heap size methodOne(getRestApiQueryResponseJson(), 'records'); // Verbose methodTwo(getRestApiQueryResponseJson(), 'records'); // Efficient /** * Method 01: very readable and verbose, great way of showing what we're doing and how much memory we can save * Heap size = 670119 byte <-- Quite a bit of memory used here for just */ void methodOne(String jsonString, String topLevelAttribute){ // Register our starting limits System.debug('[METHOD 01 - VERBOSE]'); Integer startCpuTime = Limits.getCpuTime(); Integer startHeapSize= Limits.getHeapSize(); // Let's deserialize the response body untyped Map<String,Object> myMap = (Map<String,Object>) JSON.deserializeUntyped(jsonString); // We extract the object list that we want to target based on the attribute name Object[] objectList = (Object[]) myMap.get(topLevelAttribute); // We want to be able to read data from each object in the object list, so we need to cast it to an object map (Map<String,Object>>) List<Map<String,Object>> objectMapList = new List<Map<String,Object>>(); // We iterate the list of objects for(Object obj : objectList){ // We cast the object to an object map and add it to the output list Map<String,Object> objectMap = (Map<String,Object>) obj; objectMapList.add(objectMap); } // Call the processing logic handleRecordProcessing(objectMapList); // Output the limits info for performance measuring System.debug('Heap size: ' + (Limits.getHeapSize()- startHeapSize)); } /** * Method 02: We have the heavy lifting done by the cys * Heap size = 19 bytes <-- Wow!!! almost nothing used now :-) */ void methodTwo(String jsonString, String topLevelAttribute){ // Register our starting limits System.debug('[METHOD 02 - MEMORY EFFICIENT]'); Integer startHeapSize= Limits.getHeapSize(); // Call the processing logic, but give our new flashy method as an argument this time handleRecordProcessing( getObjectMapListFromTopLevelAttribute( (Map<String,Object>) JSON.deserializeUntyped(jsonString), topLevelAttribute ) ); // Output the limits info for performance measuring System.debug('Heap size: ' + (Limits.getHeapSize() - startHeapSize)); } /** * Method that contains the logic to process the records * In this example it just outputs the Id and Name of the record */ void handleRecordProcessing(List<Map<String,Object>> objectMapsToProcess){ for(Map<String,Object> objectMap : objectMapsToProcess){ //System.debug('Id: ' + objectMap.get('Id') + ' - Name:' + objectMap.get('Name')); } } /** * Method that receives an untyped deserialized JSON response where one of the top level attributes * is a list of objects you needs to convert to Object maps (Map<String,Object>) in a memory efficient way * * @param objectMap The type casted untyped JSON --> (Map<String,Object>) JSON.deserializeUntyped(jsonString); * @param attributeName the top level attributeName that represents a list of objects inside of the JSON * @return a list of object maps that are now usable in the code */ public static List< Map<String,Object> > getObjectMapListFromTopLevelAttribute(Map<String,Object> objectMap, String attributeName){ // Create a list of Object Maps to store out output List<Map<String,Object>> outputList = new List<Map<String,Object>>(); // Iterate the object list from the input map, note that we cast it in the loop for(Object obj : (Object[]) objectMap.get(attributeName)){ // Validate that the object is actually an object and NOT a list // Cast the objects to Object Maps inside the add() methods parameter if(obj instanceof Map<String, Object>){ outputList.add((Map<String,Object>) obj); } } // Return our lovely new list of objects maps that we can now use without having wasted valuable heap space return outputList; } /** * Execute an HTTP call the the REST API that queries 10k account records with just the name populated * Return the response body JSON String containing these object. * Note: There is no real error handling here */ private String httpResponseBody; public String getRestApiQueryResponseJson(){ if(httpResponseBody == null){ // Create a default request HttpRequest httpRequest = new HttpRequest(); httpRequest.setMethod('GET'); httpRequest.setEndpoint('https://api-test-service.herokuapp.com/api/sfdc-account-query?numberOfRecords=10000&prettyPrint=0'); // Send the request and retrieve the JSON body httpResponseBody = new Http().send(httpRequest).getBody(); } return httpResponseBody; }
Comments