[SalesForce] How should I properly format a Date within an SObject parameter to a RemoteAction method

I'm having trouble sending Date values from the client with remoted methods. If my RemoteAction method takes a plain Date value, everything works fine with the suggestion of using "toUTCString" which I found here. Unfortunately this technique does not appear to work for Date values that are parts of SObjects (either specific ones such as Contact or the anonymous "SObject" type).

Test case controller:

public with sharing class DateRemotingTest {
@RemoteAction
public static void acceptDate(Date d) {
    System.debug('got date:' + String.valueOf(d));  // works
}

@RemoteAction
public static void acceptContact(Contact c) {
    insert c;                                       // fails
    System.debug('got Contact with date:' + String.valueOf(c.BirthDate));
    delete c;
}
}

Test case page:

<apex:page controller="DateRemotingTest">
<script>
DateRemotingTest.acceptDate((new Date()).toUTCString(),
                            function(result, event) {
                                if (event.status) {
                                    console.log('plain date worked');
                                } else {
                                    console.log('plain date had some kind of error: ' + event.message);
                                }});
DateRemotingTest.acceptContact({LastName: 'Xi',
                                FirstName: 'JinPing',
                                Birthdate: (new Date(1953,5,1)).toUTCString()
                                },
                                function(result, event) {
                                    if (event.status) {
                                        console.log('plain date worked');
                                    } else {
                                        console.log('plain date had some kind of error: ' + event.message);
                                    }
                                });

</script>
</apex:page>

Loading the page results in the error

Insert failed. First exception on row 0; first error: INVALID_TYPE_ON_FIELD_IN_RECORD, Birthdate: value not of required type: Mon, 01 Jun 1953 07:00:00 GMT

I have tried numerous variations on the format, but the server isn't happy with any of them. What is the correct way of doing this?

Edit: I've created a much fancier test case – almost a console for experimenting with Date serialization style. controller and page.

Best Answer

UPDATE: 9th Feb 2013. This issue has now been fixed by Salesforce from Spring'13


Yes this looks like a bug to me, I would raise a case with Salesforce with your repo code. The deserializer is placing invalid values into the SObject fields. If you comment out the insert and delete DML operations and just leave String.valueOf(contact.BirthDate) you get a nice Java internal error, 'java.lang.String cannot be converted to java.util.Date' :)

Workaround:

Based on the bug manifesting around serialising / deserialising SObject Date fields, I created a wrapped Apex class that used Apex Properties to created an Apex Date accessor to the underlying SObject Date field. Like so...

@RemoteAction
public static String acceptContact(WrappedContact wc) {
    insert wc.contact;
    delete wc.contact;
    return 'got Contact with date:' + String.valueOf(wc.contact.BirthDate);
}

public class WrappedContact
{
    public Contact contact;
    public Date birthDate { get { return contact.BirthDate; } set { contact.Birthdate = value; } }
}

This is the JavaScript code...

DateRemotingTest.acceptContact(
     {
        BirthDate: new Date(1953,5,1).toUTCString(),
        Contact: 
        {
           LastName: 'Xi',
           FirstName: 'JinPing'
        }
     },
     function(result, event) 
        {
            if (event.status) {
                console.log('plain date worked ' + result);
            } else {
                console.log('plain date had some kind of error: ' + event.message);
            }
        }
);

The emits to the browser console...

plain date worked1353196800000

plain date worked got Contact with date:1953-05-31

UPDATE:

Well the JSON serializer in Apex works just fine, which I would have expected to share the same underlying code TBH.

String cjson = '{"attributes":{"type":"Contact"},"Birthdate":"2012-11-18"}';
Contact newc = (Contact) JSON.deserialize(cjson, Contact.class);
System.debug('Date is ' + newc.BirthDate);

With this knowledge you could consider passing a JSON string parameter via JavaScript Remoting and using this JSON.deserialize manually. I can put together a sample for that if nothing else turns up. Agree its very frustrating! :-(

Related Topic