5

I am in learning phase and strucked that what to choose JSON generator or JSON parser when response is coming from 3rd party and type REST webservice.

In Apex guide it showing

Using the JSONGenerator class methods, you can generate standard JSON-encoded content. Use the JSONParser class methods to parse JSON-encoded content.

Can anyone please guide me with example.

1 Answer 1

9

The two are opposite features. The JSONGenerator takes data input and outputs JSON strings. The JSONParser takes JSON string input and outputs objects.

If you're sending data to an outside source, either for a client calling your code, or sending data to a server, use the generator. If you're receiving data from an outside source, either from a client or from a server response, use the parser.

/*************************************************************************\
|  /--------\  Call to SFDC    /-----------\   Http Callout   /--------\  |
|  |        | ---- Parser ---> |           | -- Generator --> |        |  |
|  | Client |                  | Apex Code |                  | Server |  |
|  |        | <-- Generator -- |           | <--- Parser ---- |        |  |
|  \--------/   Return Data    \-----------/   Http Response  \--------/  |
\*************************************************************************/

However, if you want efficient code, you should use neither, and stick with JSON.serialize, JSON.deserialize, or JSON.deserializeUntyped. JSON.serialize is a quicker version of the JSONParser, and the deserialize methods are a quicker version of the JSONGenerator.

The JSONGenerator has an example, which I'll copy-paste for you here:

public class JSONGeneratorSample{

    public class A { 
        String str;

        public A(String s) { str = s; }
    }

    static void generateJSONContent() {
        // Create a JSONGenerator object.
        // Pass true to the constructor for pretty print formatting.
        JSONGenerator gen = JSON.createGenerator(true);

        // Create a list of integers to write to the JSON string.
        List<integer> intlist = new List<integer>();
        intlist.add(1);
        intlist.add(2);
        intlist.add(3);

        // Create an object to write to the JSON string.
        A x = new A('X');

        // Write data to the JSON string.
        gen.writeStartObject();
        gen.writeNumberField('abc', 1.21);
        gen.writeStringField('def', 'xyz');
        gen.writeFieldName('ghi');
        gen.writeStartObject();

        gen.writeObjectField('aaa', intlist);

        gen.writeEndObject();

        gen.writeFieldName('Object A');

        gen.writeObject(x);

        gen.writeEndObject();

        // Get the JSON string.
        String pretty = gen.getAsString();

        System.assertEquals('{\n' +
        '  "abc" : 1.21,\n' +
        '  "def" : "xyz",\n' +
        '  "ghi" : {\n' +
        '    "aaa" : [ 1, 2, 3 ]\n' +
        '  },\n' +
        '  "Object A" : {\n' +
        '    "str" : "X"\n' +
        '  }\n' +
        '}', pretty);
    }
}

The JSONParser also has an example, which I've also included here.

public static void parseJSONString() {
    String jsonStr = 
        '{"invoiceList":[' +
        '{"totalPrice":5.5,"statementDate":"2011-10-04T16:58:54.858Z","lineItems":[' +
            '{"UnitPrice":1.0,"Quantity":5.0,"ProductName":"Pencil"},' +
            '{"UnitPrice":0.5,"Quantity":1.0,"ProductName":"Eraser"}],' +
                '"invoiceNumber":1},' +
        '{"totalPrice":11.5,"statementDate":"2011-10-04T16:58:54.858Z","lineItems":[' +
            '{"UnitPrice":6.0,"Quantity":1.0,"ProductName":"Notebook"},' +
            '{"UnitPrice":2.5,"Quantity":1.0,"ProductName":"Ruler"},' +
            '{"UnitPrice":1.5,"Quantity":2.0,"ProductName":"Pen"}],"invoiceNumber":2}' +
        ']}';

    // Parse entire JSON response.
    JSONParser parser = JSON.createParser(jsonStr);
    while (parser.nextToken() != null) {
        // Start at the array of invoices.
        if (parser.getCurrentToken() == JSONToken.START_ARRAY) {
            while (parser.nextToken() != null) {
                // Advance to the start object marker to
                //  find next invoice statement object.
                if (parser.getCurrentToken() == JSONToken.START_OBJECT) {
                    // Read entire invoice object, including its array of line items.
                    Invoice inv = (Invoice)parser.readValueAs(Invoice.class);
                    system.debug('Invoice number: ' + inv.invoiceNumber);
                    system.debug('Size of list items: ' + inv.lineItems.size());
                    // For debugging purposes, serialize again to verify what was parsed.
                    String s = JSON.serialize(inv);
                    system.debug('Serialized invoice: ' + s);

                    // Skip the child start array and start object markers.
                    parser.skipChildren();
                }
            }
        }
    }
} 

// Inner classes used for serialization by readValuesAs(). 

public class Invoice {
    public Double totalPrice;
    public DateTime statementDate;
    public Long invoiceNumber;
    List<LineItem> lineItems;

    public Invoice(Double price, DateTime dt, Long invNumber, List<LineItem> liList) {
        totalPrice = price;
        statementDate = dt;
        invoiceNumber = invNumber;
        lineItems = liList.clone();
    }
}  

public class LineItem {
    public Double unitPrice;
    public Double quantity;
    public String productName;
}

As you can see, reading and writing are both very tedious to do, and you should consider using these classes only as a last resort.

8
  • In addition to readability (worse using these classes) I am curious how the performance compares. With serialization/deserialization being so slow on the platform, I imagine these must be faster, but even so it doesn't seem worth the tradeoff.
    – Adrian Larson
    Commented Oct 19, 2016 at 1:56
  • 3
    @AdrianLarson JSON methods are approximately 10-15% faster than JSONGenerator/JSONParser methods, and you don't have to write your own custom parsing loops. I suspect that, internally, the JSON methods use the parser/generator classes, but are still more efficient because the runtime does not check for governor limits as frequently inside built-in methods. Of course, that's only conjecture, but seems to make sense logically.
    – sfdcfox
    Commented Oct 19, 2016 at 2:10
  • 1
    So more hassle and slower. I feel even better about my disdain for their use.
    – Adrian Larson
    Commented Oct 19, 2016 at 2:11
  • @AdrianLarson Hey, they're just as useful as String.equalsIgnoreCase...
    – sfdcfox
    Commented Oct 19, 2016 at 2:12
  • 1
    At least that doesn't add a bunch of LOC and hurt readability though. I'd take one line of useless over some of the 200+ LOC parsers/generators I've seen that could have been one line.
    – Adrian Larson
    Commented Oct 19, 2016 at 2:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .