10

I need to easily serialize (save as long text field in database) and deserialize (convert back to a class) a parameter list in Apex of String -> Object value pairs.

My first idea was just to write a class like this...:

public class Parameters{
    private Map<String, Object> parameters = new Map<String, Object>();

    public void add(String name, Object value) {
        this.parameters.put(name, value);
    }

    public Object get(String name) {
        Object result = null;

        if(this.parameters.containsKey(name)) {
            result = this.parameters.get(name);
        }
        return result;
    }    
} 

... and use JSON.serialize and deserialize..

Parameters params = new Parameters();
params.add('Name', 'Robert');
params.add('Age', 36);
String serialized = JSON.serialize(params);
Parameters deserialized = (Parameters) JSON.deserializeStrict(serialized, Parameters.class);
System.assertEquals(params, deserialized);

but then I got this error message:

System.JSONException: Apex Type unsupported in JSON: Object

Any idea or experience on how to implement such a Parameter class that is able to at least hold all basic (non-collection) types?!

12

Rational for Error: JSON does not encoded the data types of the data, thus you have to give your class type to allow it to understand how to parse the data as it works its way through the class members. The Object data type is not enough for the deserialize method to know the data type.

Using JSON.deserializeUntyped. To work around this you can manually parse the JSON using the various JSON parser methods or use the deserializeUntyped method which returns conveniently a map that contains primitive data types!

So I've leveraged this in some new methods to encapsulate this with your Parameters class.

public class Parameters{
    private Map<String, Object> parameters = new Map<String, Object>();

    public void add(String name, Object value) {
        this.parameters.put(name, value);
    }

    public Object get(String name) {
        Object result = null;

        if(this.parameters.containsKey(name)) {
            result = this.parameters.get(name);
        }
        return result;
    }    

    public String serialize()
    {
        return JSON.serialize(parameters);      
    }

    public static Parameters deserialize(String serialized)
    { 
        Parameters parameters = new Parameters();
        parameters.parameters = (Map<String, Object>) JSON.deserializeUntyped(serialized);
        return parameters;
    }
}

This is a slightly modified version of your test code to use the new helper methods.

Parameters params = new Parameters();
params.add('Name', 'Robert');
params.add('Age', 36);
String serialized = params.serialize();
Parameters deserialized = Parameters.deserialize(serialized);
System.assertEquals(params.toString(), deserialized.toString());

I've used toString to compare equality, as without it the check fails, as the two variables point to different instances of the same object.

Alternative:

This naked version also works as well...

Map<String, Object> parameters = new Map<String, Object>();
parameters.put('A', 36);
parameters.put('B', 'Robots');
String serialized = JSON.serialize(parameters);
System.debug(serialized);
parameters = (Map<String, Object>) JSON.deserializeUntyped(serialized);
System.debug(parameters.get('B'));
  • 1
    your get() method can just be this.parameters.get(name); you don't need the containsKey check – superfell May 31 '13 at 17:58
  • thanks @superfell, your correct, i spotted that, but since that wasn't part of the question i left it, so i copied this bit directly in my revised version which contains the additional JSON methods. – Andrew Fawcett May 31 '13 at 18:00
  • Wow! I should open a bounty just to give you enough credit for this...But you already have so much points ;-) Thanks a lot Andrew. – Robert Sösemann May 31 '13 at 18:32
  • 1
    Pleasure as always Robert, glad you liked it! :) – Andrew Fawcett Jun 1 '13 at 9:14
  • 2
    @csteddy You need to cast for each layer. E.g. { "a": { "1": 1, "2": 2} could be read as ((Map<String,Object>) data.get('a')).get('2') – ca_peterson Sep 17 '13 at 3:05

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.