[SalesForce] Deserialize JSON Body into two different Lists of own classes

I'm writing an REST PUT request that takes in an array of Careers and Degrees from the body and converts them to inner classes within the RestResource class. However, when I am attempting to deserialize the body string to these respected object, I get the error

Unexpected character ('(' (code 40)): expected a valid value (number, String, array, object, 'true', 'false' or 'null') at input location [1,2]

Here are my classes:

class Career {
    Integer drupalId;
    String name;
    List<Integer> degrees;

    public Career(Integer drupalId, String name, List<Integer> degrees) {
        this.drupalId = drupalId;
        this.name = name;
        this.degrees = degrees;
    }
}

class Degree {
    Integer drupalId;
    String name;

    public Degree(Integer drupalId, String name) {
        this.drupalId = drupalId;
        this.name = name;
    }
}

Here is the logic of parsing the data:

// Get Request
Map<String, Object> requestBody = (Map<String, Object>)JSON.deserializeUntyped(req.requestBody.toString());

// Parse request body
Object careerObjects = requestBody.get('careers');
Object degreeObjects = requestBody.get('degrees');

String errorString = '';
Boolean errored = false;
if (careerObjects == null) {
    errorString += '\'careers\' not provided\n';
    errored = true;
} else if (degreeObjects == null) {
    errorString += '\'degrees\' not provided\n';
    errored = true;
}
if (errored) {
    res.responseBody = Blob.valueOf(errorString);
    res.statusCode = 422;
    return;
}

String careersJsonString = String.valueOf(careerObjects); 
String degreesJsonString = String.valueOf(degreeObjects); 

System.debug(careersJsonString);
System.debug(degreesJsonString);

List<Object> careers = (List<Object>)JSON.deserialize(careersJsonString, List<Object>.class);
List<Degree> degrees =  (List<Degree>)JSON.deserialize(degreesJsonString, List<Degree>.class);

System.debug(careers);
System.debug(degrees);

Here is my Request body

{
  "careers": [
    { 
      "drupalId": 1,
      "name": "Career 1",
      "degrees": [
        1,
        2
      ]
    },
    { 
      "drupalId": 2,
      "name": "Career 2",
      "degrees": [
        2,
        3
      ]
    },
    { 
      "drupalId": 3,
      "name": "Career 3",
      "degrees": [
        1,
        3
      ]
    }
  ],
  "degrees": [
    { 
      "drupalId": 1,
      "name": "Degree 1"
    },
    { 
      "drupalId": 2,
      "name": "Degree 2"
    },
    { 
      "drupalId": 3,
      "name": "Degree 3"
    }
  ]
}

When I run this, the first two logs print out the two json parts as arrays as expected:

CareerJsonString: ({degree=(1,2), drupalId=1, name=Career 1}, { ... }, { ... })
DegreeJsonString: ({drupalId=1, name=Degree 1}, { ... }, { ... })

But then when I attempt to deserialize right after that step, it errors out with the error I explained above. How else am I suppose to deserialize these 2 objects?

Best Answer

From your 2 System.debug:

CareerJsonString: ({degree=(1,2), drupalId=1, name=Career 1}, { ... }, { ... }) 
DegreeJsonString: ({drupalId=1, name=Degree 1}, { ... }, { ... })

These 2 are not JSON. These are just Map objects printed as STRING. (No quotes saying its not JSON)

A quick fix would be, to serialize back into JSON:

String careersJsonString = JSON.serialize(careerObjects); 
String degreesJsonString = JSON.serialize(degreeObjects); 

But does it make sense to go back and forth?

A better approach will be to create a whole wrapper altogether using Json2Apex:

//
//Generated by AdminBooster
//

public class JSONOuterWrapper{
    public cls_careers[] careers;
    public cls_degrees[] degrees;
    class cls_careers {
        public Integer drupalId;    //1
        public String name; //Career 1
        public Integer [] degrees;
    }
    class cls_degrees {
        public Integer drupalId;    //1
        public String name; //Degree 1
    }
    public static JSONOuterWrapper parse(String json){

        return (JSONOuterWrapper) System.JSON.deserialize(json, JSONOuterWrapper.class);
    }


}

Test code:

String input ='{"careers":[{"drupalId":1,"name":"Career 1","degrees":[1,2]},{"drupalId":2,"name":"Career 2","degrees":[2,3]},{"drupalId":3,"name":"Career 3","degrees":[1,3]}],"degrees":[{"drupalId":1,"name":"Degree 1"},{"drupalId":2,"name":"Degree 2"},{"drupalId":3,"name":"Degree 3"}]}';

JSONOuterWrapper hw = (JSONOuterWrapper)JSON.deserialize(input, JSONOuterWrapper.class);

System.debug(hw.careers);
System.debug(hw.degrees);
Related Topic