2

I have been developing an Apex Trigger where I build a json string from an incomming Event.

What I do is serialize the event into the json at first, then deserialize it as a Map and add to it some new entries. Finally I serialize the Map into a String and store it within a field named 'Json__c' of a custom object 'Queue__c' and insert it into the DB. The problems are coming when I find that the final value inserted is the first json that I serialize at first, when it should be the last one!

I attach you a summary of my code so that you can better understand what I'm doing:

Queue__c queue = new Queue__c();
String serializedJson = JSON.serialize(event);
Map<String, Object> jsonAsMap = (Map<String, Object>) JSON.deserializeUntyped(serializedJson);
// The variable ownerId is coming with its correct value
jsonAsMap.put('Owner.Id', ownerId);
queue.Json__c = JSON.serialize(jsonAsMap);
Database.SaveResult[] srList = Database.insert(queue);

Within those lines of code, I have written a System.debug() above the INSERT and it gives me the right value of queue.Json__c. However, when I check the value of the new record in the DB I see that queue.Json__c is equal to the 'serializedJson' variable that appears in my code instead of being equal to the last JSON.serialize output.

It is like the insert is forgetting about the changes that I put into 'jsonAsMap' variable, but I cannot understand how that is possible. There is also nothing wrong in the SaveResult list. Why is this happening? Am I missing any concept?

4
  • Is this the exact code that is giving the issue? Jan 15, 2015 at 12:47
  • Nope, it is very long but the only thing that I do is put and remove from the map.
    – Martin
    Jan 15, 2015 at 12:55
  • Did you try to put OwnerId in the map value ie. Without the "."?
    – zokito
    Jan 15, 2015 at 16:06
  • Sorry for the first perhaps a bit silly comment ... I tried your code but on the Contact in execute anonymous mode and it works. Pseudo code: Load contact, serialize to JSON, load in map, set "Owner.Id", "ownerId", set Contact.Description to the new serialized value. There must be something on your org that's preventing the save.
    – zokito
    Jan 17, 2015 at 21:34

1 Answer 1

2

The reason I asked to see all of the code is because sometimes when working with large sets of code, passing variables in and out of methods can have unexpected side effects. Is it possible you are having an issue with passing variables into and back out of methods? Apex uses pass by value for primitive data types (such as a Map or String). If at any point you set jsonAsMap = <something> you could be running into this issue. Here is a perfect example from the reference:

We’ll illustrate this with some code samples. But first, let’s step back and define these terms.

“Pass by value” means when a method is called, a second copy of the parameter variable is made in memory, and this copy is passed to the method as a parameter. This copy can be modified in the method, but the original variable in the caller is unchanged, and the changes to the copy are lost upon return.

“Pass by reference” means when a method is called, that actual variable is passed to the method.

As described in the new developer’s guide text, Apex is not passing anything by reference. It is passing the reference (i.e., the memory address) by value, which allows the developer to change fields on the object and call methods (like list.add()) on the object.

Let’s illustrate with some code. First, an example where we get apparent pass-by-reference behavior:

List fillMe = new List();
PassByWhatNow.reference(fillMe);
System.assertEquals(fillMe.size(),5);   //five items, as expected

/*  calls this method
public static void reference(List m) {
    List la = [select id, name from Account limit 5];
    for (Account a : la) m.add(a);
}
*/

In this example, the parameter passed to the function, behind the scenes, is a pointer to the fillMe collection, passed by value. That is to say, we took the memory address and copied it – but it is the same memory address number in both places. When the add() function is called on the copy, that same memory location is modified by adding the specified items to the list. So when we return to the calling program, the modifications made in the static function are visible. So far, so good.

Now let’s look at an example where things break down.

List createMe = new List();
PassByWhatNow.referenceNew(createMe);
System.assertEquals(createMe.size(),0);   //nothing in the list

/* calls this method
public static void referenceNew(List m) {
    m = new List([select id, name from Account limit 5]);
}
*/

Again, we pass a copy of the list’s memory address to the function. However, this time, the function is initializing the variable anew. When the “new” function is called, new memory is allocated. This is the big difference.

The copy of the memory address passed as a parameter is overwritten with the address of the newly allocated memory. The original, however, is not overwritten. That change in address is not known to the caller!

Any subsequent actions done in the method are on that new memory address rather than the original object address. These changes, including the addition of the Accounts to the list, can not be available to the caller, since it only knows of the original address. No actions were done on this address; the list on the caller is therefore unchanged, still empty as it was when the call was made.

While Apex usually does behave as if we’re passing variables by reference, we’re not truly passing by reference. There are a few situations where the distinction is important, as detailed here. Now you know more, and you are a stronger developer.

3
  • I understand what you are explaining and I thank you your complete comment to guide me through the possible error that may be causing this behaviour.
    – Martin
    Jan 15, 2015 at 13:26
  • 1
    Sorry, my comment got cut: I understand what you are explaining and I thank you your complete comment to guide me through the possible error that may be causing this behaviour. The thing is that I use System.debug(queue.Json__c) just before the execution of the INSERT and the value is the correct one. Then INSERT comes and inserts the incorrect string, don't know why it would say in the DEBUG that it is correct and then insertion would 'fail'.
    – Martin
    Jan 15, 2015 at 13:37
  • Ah, that makes sense. Odd issue... Jan 15, 2015 at 13:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .