├── src ├── classes │ ├── JSONReservedSerializer.cls-meta.xml │ ├── JSONReservedSerializer_Tests.cls-meta.xml │ ├── JSONReservedSerializer_Tests.cls │ └── JSONReservedSerializer.cls └── package.xml └── README.md /src/classes/JSONReservedSerializer.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 38.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/JSONReservedSerializer_Tests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 38.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JSONReservedSerializer 5 | JSONReservedSerializer_Tests 6 | ApexClass 7 | 8 | 38.0 9 | 10 | -------------------------------------------------------------------------------- /src/classes/JSONReservedSerializer_Tests.cls: -------------------------------------------------------------------------------- 1 | @isTest 2 | public class JSONReservedSerializer_Tests { 3 | 4 | @isTest 5 | private static void testRoundTrip(){ 6 | String origString = '{"object":{"notReserved":"abc","private":true}}'; 7 | 8 | MySerializer myJSON = new MySerializer(); 9 | 10 | //deserialization 11 | MyDTO obj = (MyDTO) 12 | myJSON.deserialize( 13 | origString, 14 | MyDTO.class 15 | ); 16 | 17 | //serialization 18 | String newString = myJSON.serialize(obj, MyDTO.class); 19 | System.assertEquals(origString, newString); 20 | } 21 | 22 | // CLASS FOR TESTING 23 | public class MySerializer extends JSONReservedSerializer { 24 | public MySerializer() { 25 | //setup mappings 26 | super(new Map>{ 27 | MyDTO.class => new Map { 28 | 'obj' => 'object', 29 | 'isPrivate' => 'private' 30 | } 31 | }); 32 | } 33 | } 34 | 35 | //define DTO's using mapped names 36 | public class MyDTO { 37 | public MyInnerDTO obj; 38 | } 39 | 40 | public class MyInnerDTO { 41 | public Boolean isPrivate; 42 | public String notReserved; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reserved Keyword Serializer 2 | A Utility class for better control over JSON serialization/deserialization in salesforce apex 3 | 4 | ## Install 5 | 6 | 1. `git clone` 7 | 1. `cd` into folder 8 | 1. `sfdx force:mdapi:deploy -u [username] -d ./src -w 10000` 9 | 10 | ## Usage 11 | 12 | ### extend 13 | 14 | For any JSON you need to Serialize data structure you need to seralize: 15 | 16 | 1. implement a class that `extends JSONReservedSerializer` 17 | 1. pass mappings into the `super()` constructor. Mapping is defined by `Map>` where `Type` is the top level object you are serializing. This allows for seralizaiton of multiple types in a single class. 18 | 19 | ```java 20 | public class MySerializer extends JSONImprovedSerializer { 21 | 22 | private MySerializer() { 23 | //setup mappings 24 | super(new Map>{ 25 | MyOuterDTO.class => OUTER_DTO_MAPPINGS 26 | }); 27 | } 28 | 29 | //define DTO's using mapped names 30 | static final Map OUTER_DTO_MAPPINGS = new Map { 31 | 'obj' => 'object', 32 | 'isPrivate' => 'private' 33 | }; 34 | 35 | public class OuterDTO { 36 | public InnerDTO obj; 37 | } 38 | 39 | public class InnerDTO { 40 | public Boolean isPrivate; 41 | public String notReserved; 42 | } 43 | } 44 | ``` 45 | 46 | ### Serialize / Deserialize 47 | 48 | ```java 49 | 50 | String origString = '{"object":{"private":true,"notReserved":"abc"}}'; 51 | 52 | //deserialization 53 | MySerializer json = new MySerializer(); 54 | MySerializer.OuterDTO dto = (MySerializer.OuterDTO) json.deserialize( 55 | origString, 56 | MySerializer.OuterDTO.class 57 | ); 58 | 59 | //serialization 60 | String newString = json.serialize(obj, MySerializer.OuterDTO.class); 61 | System.assertEquals(origString, newString); 62 | ``` 63 | 64 | ### Notes 65 | 66 | 1. Serialization mappings are global to the entire object 67 | 1. Likely will fail due to limit exceptions with extremely large strings 68 | -------------------------------------------------------------------------------- /src/classes/JSONReservedSerializer.cls: -------------------------------------------------------------------------------- 1 | /* Author: Charlie Jonas (charlie@callawaycloudconsulting.com) 2 | * Description: Allows reserved named serialization. 3 | * Usage: See Readme @ https://github.com/ChuckJonas/APEX-JSONReservedNameSerializer 4 | */ 5 | public abstract class JSONReservedSerializer { 6 | private final Map> typeMapKeys; 7 | 8 | public JSONReservedSerializer(Map> typeMapKeys){ 9 | this.typeMapKeys = typeMapKeys; 10 | } 11 | 12 | public String serialize(Object obj, System.Type type){ 13 | return serialize(obj, false, type); 14 | } 15 | 16 | public String serialize(Object obj, Boolean suppressNulls, System.Type type){ 17 | String retString = JSON.serialize(obj, suppressNulls); 18 | retString = transformStringForSerilization(retString, typeMapKeys.get(type)); 19 | return retString; 20 | } 21 | 22 | public Object deserialize(String jsonString, System.Type type){ 23 | jsonString = transformStringForDeserilization(jsonString, typeMapKeys.get(type)); 24 | return JSON.deserialize(jsonString, type); 25 | } 26 | 27 | private static String transformStringForSerilization(String s, Map mapKeys){ 28 | if(mapKeys == null){ 29 | return s; 30 | } 31 | return replaceAll(s, mapKeys); 32 | } 33 | 34 | private static String transformStringForDeserilization(String s, Map mapKeys){ 35 | if(mapKeys == null){ 36 | return s; 37 | } 38 | Map flippedMap = new Map(); 39 | for(String key : mapKeys.keySet()){ 40 | flippedMap.put(mapKeys.get(key), key); 41 | } 42 | return replaceAll(s, flippedMap); 43 | } 44 | 45 | private static String replaceAll(String s, Map toFromMap){ 46 | for(String key : toFromMap.keySet()){ 47 | s = s.replaceAll('"'+key+'"(\\ )*:', '"'+toFromMap.get(key)+'":'); 48 | } 49 | return s; 50 | } 51 | } 52 | --------------------------------------------------------------------------------