I like the way JavaScript lets you easily overlay two objects, retaining the properties of both:
let obj1 = {name: 'Foo', quantity: 3};
let obj2 = {name: 'Bar', description: 'A very nice bar'};
// Merge the objects. Where these object share properties, obj2 will "win"
let newObj = {...obj1, ...obj2};
console.log(JSON.stringify(newObj));
// Console output:
// {'name': 'Bar', 'quantity': 3, 'description': 'A very nice bar'};
I often find myself needing to do something similar in Apex when dealing with SObject records of the same type. For example, when dealing with duplicates, or when working with dummy SObject records from test utilities.
I have a method for this, but it feels pretty heavy for what ought to be a simple task, relying (as it does) on a getDescribe()
call:
// Push all populated, updateable field values from one SObject to another
// SObject of the same type
public static SObject transferSObjectFieldValues(
SObject targetObject,
SObject sourceObject,
Boolean writeBlank
) {
Map<String, Schema.SObjectField> fieldMap = targetObject.getsObjectType()
.getDescribe().fields.getMap();
Map<String, Object> sourceFields = sourceObject.getPopulatedFieldsAsMap();
for (String fieldName : sourceFields.keySet()) {
Object value = sourceFields.get(fieldName);
if (fieldMap.containsKey(fieldName)
&& fieldMap.get(fieldName).getDescribe().isUpdateable()
&& (writeBlank ||
(value != null &&
!(value instanceof String &&
String.isBlank((String)value))))) {
targetObject.put(fieldName, sourceFields.get(fieldName));
}
}
return targetObject;
}
Is there something more lightweight and straightforward I could be doing?
getPopulatedFieldsAsMap()
already, but it seems like you still need agetDescribe()
call, or you end up hitting "Field is not writeable" exceptions when you try to loop through that map and assign its values.