Most of your variables are superfluous, and you could clean it up so it'd be easier to read.
The main problem is that you're never breaking out of your innermost loop, and so the same lead record keeps getting used over and over again. You need to test for the END_OBJECT, and when you get there, add the record to the list and then start over again. The innermost loop should read while(parser.nextToken() != JSONToken.END_OBJECT)
, and the one outside that should technically be while(parser.nextToken() != JSONToken.END_ARRAY)
. However, using a simple state machine, which I've included here, you can eliminate most of the complexity, along with a map that translates field names into values.
Here's a simple version of how I'd accomplish the same task:
Map<String, SobjectField> fieldMap = new Map<String, SObjectField> {
'first name' => Lead.FirstName,
'last name' => Lead.LastName,
'email' => Lead.Email // keep going!
};
Lead tempLead;
Lead[] leadList = new Lead[0];
String fieldName;
while(parser.nextToken() != null) {
// Save field name, next round we'll get the value
if(parser.getCurrentToken() == JsonToken.FIELD_NAME) {
fieldName = parser.getText();
continue;
}
// Special case-- if the field name isn't null, we know a value is here
if(fieldName != null && fieldMap.containsKey(fieldName)) {
tempLead.put(fieldMap.get(fieldName), parser.getText());
fieldName = null;
continue;
}
// We check for a new object later, because it's a rarer event.
if(parser.getCurrentToken() == JsonToken.START_OBJECT) {
tempLead = new Lead();
continue;
}
// Once we know end of object, we can start a new record.
if(parser.getCurrentToken() == JsonToken.END_OBJECT) {
leadList.add(tempLead);
tempLead = null;
continue;
}
}
This isn't the only right answer, but hopefully it'll get you where you want to go.
The method JSON.deserializeUntyped works well for this type of problem. What you get returned is a map:
Map<String, Object> m = (Map<String, Object>) JSON.deserializeUntyped(jsonString);
You can use the normal map methods to get hold of the keys or to see if a key is present. So for example to access the "ideal" list items:
List<Object> ideals = (List<Object>) m.get('ideal');
if (ideals != null) {
for (Object ideal : ideals) {
String product = (String) ideal('product');
String percent = (String) ideal('percent');
String dollarAmount = (String) ideal('dollarAmount');
...
}
}
Because it is known that the data is a list (array) I've just cast the object to a list. If the content is of very unpredictable type you can also use instanceof
tests in your logic.
Here is your JSON having been formatter by http://jsonformatter.curiousconcept.com/; this sort of formatting makes the JSON easier to understand:
{
"ideal":[
{
"product":"4",
"percent":"25",
"dollarAmount":"11250"
},
{
"product":"5",
"percent":"23",
"dollarAmount":"10350"
},
{
"product":"3",
"percent":"20",
"dollarAmount":"9000"
},
{
"product":"8",
"percent":"18",
"dollarAmount":"8100"
},
{
"product":"7",
"percent":"15",
"dollarAmount":"6750"
}
],
"idealFiltered":[
{
"product":"4",
"percent":"25",
"dollarAmount":"11250"
},
{
"product":"5",
"percent":"23",
"dollarAmount":"10350"
},
{
"product":"3",
"percent":"20",
"dollarAmount":"9000"
},
{
"product":"8",
"percent":"18",
"dollarAmount":"8100"
},
{
"product":"7",
"percent":"15",
"dollarAmount":"6750"
}
],
"InBudget":[
{
"product":"4",
"percent":"70",
"dollarAmount":"7000"
},
{
"product":"8",
"percent":"30",
"dollarAmount":"3000"
}
]
}
Best Answer
You will have to use JSON.deserializeUntyped method that will deserializes a JSON representation of an appliance object into a map that contains primitive data types and further collections of primitive types. Something like below should work: