You need to sign in to do that
Don't have an account?

Automatic type casting when using sObject.put()
Hey all,
This is one of those questions when I feel like I'm probably going about a simple process the wrong way and over complicating it, but I'm not sure the alternative. So I'll ask my question and if you have a better approach, please feel free to share.
The deal is that I have an Apex REST service that allows a user to pass in an object type, and any field values in the URL.
EX : http://na2.salesforce.com/apex/reservice/contact?firstname=frank&lastname=jones&age__c=21
My code works fine for any string values, but chokes on numerics. Because I instantiate a new instance of the type of object they pass in, then I loop over all the fields in the query string and dynamically add them to the sObject. Of course as far as apex is concerned all those arguments in the query string are in fact strings, so when adding non string things to the sObject it explodes.
Ideally I could use the get describe info about the field I'm inserting to find it's type and cast the value to be inserted to the correct type, but as far as I know there isn't a way to do dynamic casting at runtime. A series of if statments is about the only alternative I see, but that feels really dirty.
This is what I have currently (you can see I'm kind of using the if statment path, trying to make it as simple as possible).
Just to be clear, this code works, it's just not as efficient/dynamic as I'd like.
public static sObject saveSObject(string objectType, string recordid, RestRequest req) { //create a generic sObject to contain the update values. sObject updateObj; //get the describe object for the type of object passed in (its just passed in as a string from the URL) Schema.sObjectType objectDef = Schema.getGlobalDescribe().get(objectType).getDescribe().getSObjectType(); //find all the fields for this object type Map<String, Schema.SobjectField> ObjectFieldsMap = objectDef.getDescribe().fields.getMap(); //this method can handle updates or inserts. If a record ID was passed in, //cast the object as the type represented by the ID. If not, just create a //new object of the type found in the object describe. if(recordId != null) { updateObj = objectDef.newSobject(recordid); } else { updateObj = objectDef.newSobject(); } // populate the object's fields by looping over all the params in the rest request. for (String key : req.params.keySet()) { // only add params if they are valid field on the object if (ObjectFieldsMap.containsKey(key)) { //figure out the type of this field so we can cast it to the correct type string fieldType = ObjectFieldsMap.get(key).getDescribe().getType().name().ToLowerCase(); //since I don't know how to do, or if it's even possible to do dynamic casting we need a //series of if statments to handle the casting to numeric types. I think all the others should //be fine if left as a string. Dates might explode, not sure. if(fieldType == 'currency' || fieldType == 'double' || fieldType == 'percent' || fieldType == 'decimal' ) { updateObj.put(key, decimal.valueOf(req.params.get(key).trim())); } else if(fieldType == 'boolean') { updateObj.put(key, Boolean.valueOf(req.params.get(key))); } else if(fieldType == 'date') { updateObj.put(key, date.valueOf(req.params.get(key))); } else { updateObj.put(key, req.params.get(key)); } } else { system.debug('Invalid field: '+ key + ' for object type ' + objectType); } } //update/insert the object upsert updateObj; //return the saved object. return updateObj; }
I haven't tested it, but something like these should work:
Let me know if it does and there is probably some place for improvement by creating the parser previously to the loop.
Thanks!
I do appreciate the reply, but unfortunatly I don't think it's quite going to work. I'm not using any JSON here (just reading params from the URL). The magic method your code uses, the readValueAs I think is a JSON only feature. If there was something like that for a string data type that would be awesome, but I don't think such a thing exists.
In this line
the parser JSON gets constructed from your parameter string, so you 'build' the JSON data.
this is a working example:
Kenji755, did you ever get this figured out? I'm running into the same issue.
Also, to the other poster: The JSON example would not help us as we need a dynamic solution and would not be able to cast something to a concrete type. As Kenji stated, it looks as if the only way is to use if/else or try/catch to figure out the type and cast from there.
I'm hitting the same issue. The best way I can think to deal with it is to:
Kind of a hassle, but at least it's an OO way ;-)
getDescribe().getType() will give you a DisplayType, but for readvalueas you need a System.Type. So you need to System.Type.forName(DisplayType) before.
String type = descMap.get(*fieldName*).getDescribe().getType().name();
*Object*.put(*fieldName*, parser.readValueAs(System.Type.forName(type)));