I do not see anything in the System JSON methods or JSON Parser methods that document the behavior that you observe. I don't see anything in the Getting Started with Apex wiki article. I don't see anything in the SOQL and SOSL guide. I also found nothing in the Salesforce Known Issues
The serialize method documentation is:
Serializes Apex objects into JSON content. The object argument is the Apex object to serialize.
The following example serializes a new Datetime value.
Datetime dt =
Datetime.newInstance(
Date.newInstance(
2011, 3, 22),
Time.newInstance(
1, 15, 18, 0));
String str = JSON.serialize(dt);
System.assertEquals(
'"2011-03-22T08:15:18.000Z"',
str);
I executed your exact code from Execute Anonymous from my Force.com IDE and observed the exact same behavior.
My conclusion is that I either am not finding the correct documentation, this is the correct behavior and the documentation is lacking, or this is a SF issue.
I also modified your SOQL to:
Contact con = [select id, lastname, firstName, accountid from Contact limit 1];
Then set the first name the same:
con.firstName = 'foo';
This does result in 'foo' being in the jsonstring.
Obviously, the workaround is to always select all of the fields that you need to appear in the jsonstring or construct the new instance like you did.
If the names of the fields you are using are the same on both objects and you don't necessarily need to use XML, you could use JSON serialize and deserialize to change the object from one type to another in your Apex code:
Account a = new Account(name='The Object\'s Name');
system.debug(a);
String aString = JSON.serialize(a);
system.debug(aString);
Opportunity o = (Opportunity) JSON.deserialize(aString,Opportunity.class);
system.debug(o);
String oString = JSON.serialize(o);
system.debug(oString);
Best Answer
I've experienced a couple gotchas and differences:
DateTimes de/serialize as quoted strings:
The serializer used by REST services can return nested result sets, for example:
For a time, the @RemoteAction serializer did not. (Until v28.0 - this is now documented).
Whacky types may be serializable, but rightly throw a System.JSONException on deserialize:
Type
Type unsupported in JSON: common.apex.runtime.bytecode.BytecodeSObjectTypeDescribeSObjectResult
No suitable constructor found for type@RemoteAction methods can serialize, but not deserialize
ENUM
valuesSObject DateTime
must be transmittedLong
unix timestamp format:but
Apex DateTime
must be transmitted in a differentUTC String
format:watch out for crazy getter/setter action. Like SoapClient class mappings in PHP, they're not called!