15

JSON.serialize supports DescribeFieldResult, meaning that I can do this:

return JSON.serialize(Account.Name.getDescribe());

However, when I try to serialize the SObject itself, I experience an exception:

return JSON.serialize(Schema.Account.SObjectType.getDescribe());

This throws the following exception:

System.JSONException: (was java.lang.NullPointerException) (through reference chain: common.api.soap.wsdl.DescribeSObjectResult["listviewable"])

Oddly, ListViewable is not in the Apex Code Developer's Guide or the SOAP API Developer's Guide, so I presume it's leaking over from the REST API based on the limited information I could find on Google about this (the documentation doesn't state that this property exists, but I found a pastebin that referenced this property (and it was nil), but it doesn't appear anywhere else.

  • 2
    certainly sounds like a bug. – superfell Aug 18 '13 at 1:31
  • As of API v42.0 this is still not fixed. While serializing in the Dev Console works fine calling the code from a trigger throws the same JSONException as reported above. – Mossi Apr 9 '18 at 23:27
10
+100

My Result and Possible "Fix". The above code works fine in my org (na11), i get "listviewable": null in my JSON, as well as lookupLayoutable which is also not documetned. I'm executing it from Execute Annoynmous. As a possible "fix" (see below for my thoughts on more durable solution), it maybe sensitive to API version of your calling Apex class, so check your metadata XML file for the latest version.

My Experience and Possible Explanation... Though in general I've personally found serialising and deserialising (more so) system data types a bit hit and miss, certainly deserialising them. If you take the JSON.serialize method documentation literally, it suggests it really only designed for Apex types...

Serializes Apex objects into JSON content.

The general JSON documentation here, also states this...

JSON serialization and deserialization support is available for sObjects (standard objects and custom objects), Apex primitive and collection types, return types of Database methods (such as SaveResult, DeleteResult, and so on), and instances of your Apex classes.

So I suspect the reason it doesnt work is some bug (?) with how its discovering fields for platform types vs Apex types, as 'private' members would be ignored in Apex classes. It may be worth raising a Salesforce support case to get them to confirm this, though they may simply quote the above to you.

In Galaxy Far Far Away... This field does seem to occur quite a way back, I found it in a partner WSDL version 8.0 (circa 2008), here, but not in the latest. So I suspect its leaking out as a 'private' internal field left over from a long forgotten time. Comparing with latest Partner WSDL, lookupLayoutable also falls into this category.

Alternative 'Custom Marhsalling' Approach... In the meantime, the main thing i can suggest is leverage the JSONGenerator methods to marshall out your own similar JSON data structure, filtering out the troublesome bits. Its more work, but will be more stable i feel. You can use a mixture of writeXXXX (where XXX is the data type) and writeObject method if you want to chance your luck with those that appear to work (such as DescribeFieldResult). Sample from the docs is here, showing how to mix these.

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);
    }
}

In Summary...

I've found serialising system data types a bit hit and miss, any time i get system errors from something as seemingly innocent as this and the docs seem to state otherwise, i'd personally step away and look for another solution that is more robust. Thus if i do then get errors I can confidently call bug. As final thought depending on who the 'client' is receiving this JSON, you may want to have it call the Salesforce REST or Partner API describe functionality directly perhaps, obviously thats more of general point here since I don't know what your use case is.

Anyway, thats pretty much all I can think on this, it is a bit frustrating to have to consider the above for a data type that is likely exactly fit for your purpose. Hopefully the above has given you some further help, insight and next steps to consider... :)

  • This is the basic route I intend to go with, but conceptually it should work, as one can serialize virtually anything, and I would expect that DescribeFieldResult and DescribeSObjectResult should either both be serializable, or neither. If it were not supported at all, I'd assume one would get cannot serialize X instead of a buggy message can't serialize null, which JSON can do (JSON.serialize(null) actually does work, as does Account a = null; JSON.serialize(a)). – sfdcfox Aug 23 '13 at 15:20
  • Yeah I agree, its frustrating, technically i think Salesforce would argue its not supported, so hence I think there answer is its not a bug. Though yes, as it standards not enforcing with a better error message what the docs states it is just a tease! :( Hopefully this answer helped clear a few things at least and give you a safe router to head down! :-) – Andrew Fawcett Aug 23 '13 at 17:33
  • Oh, and for the record, the use case is a page that is rendered entirely with remoting (yay for free API calls!); the fields are part of a managed package, so for portability between an unmanaged staging org and a managed package org, we're trying to describe the fields we use in terms of absolute values (e.g. system.fields.Product2.DiscountProduct.Name would be either namespace__Discount_Product__c or Discount_Product__c depending on the org it ran in). – sfdcfox Aug 23 '13 at 18:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.