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'));
Declare your member transient and the JSON serializer will ignore it. A quick validation in an anonymous block (yes, you can declare classes inside anonymous blocks!)
public enum Obscurity{ OBVIOUS, OPAQUE, WTF }
public class Thing{
public Obscurity obscurityLevel;
public transient Obscurity notSerialized;
}
Thing t = new Thing();
t.obscurityLevel = Obscurity.OBVIOUS;
t.notSerialized = Obscurity.OPAQUE;
System.debug(LoggingLevel.Error,JSON.serialize(t));
The debug log generated will be along the lines of:
11:24:33.092 (92520000)|USER_DEBUG|[11]|ERROR|{"obscurityLevel":{}}
Note that this will also prevent the enum from being kept in viewstate, and I believe also has some impact on Database.Batchable's state.
Another option is to coerce your object into a Map, which can be done with the builtin JSON methods, and then mutate the Map before re-serializing it with the desired state. This can be used to handle the bulk of the object via the standard JSON methods, but then specially handle the enum. I've found this much easier than using the JSONGenerator and JSONParser classes.
Best Answer
I assume this is for some historical reason as it would be convenient if it did work.
Instead you can create your own simple Apex class and convert to that:
or just create a
Map
perSelectOption
and convert to that: