Q: How to serialize a custom Salesforce Class object with nested objects to json I am a noob on serialising in SF. I have a SF object which i Want to serialise to JSON. The object contains nested data. 


*

*Do I need to create all the nested data first an add these to the outer objects? 

*I my example I create the country object an add this to the adress object. Is this the correct way to go?

*I see 3 standard fields which I cant place are these standard SF fields? 
// Status // Relationships (lookup?) //Name

*This is pretty intensive. Is there a quicker way to accomplish this? 
SF Object
    public class MyObjects {
    public List<MyAccount> Accounts;
    public List<MyContact> Contacts;
    public List<Payment> Payments;
    public List<Refund> Refunds;
    public List<MyOrder> Orders;
    public List<MyInvoice> Invoices;

    public abstract class MyBase {
        public string Id { get; set;}
        public string Code { get; set;}
        public string Name { get; set;}
        public string Status { get; set;}
        public DateTime CreatedDate { get; set; }
        public DateTime ModifiedDate { get; set; }
        public List<CustomValue> CustomValues;
        public List<Relationship> Relationships;
        //
        public Relationship AddRelationship(string objId, string objCode, string objName, string objType) {
            if (Relationships == null) {
                Relationships = new List<MyObjects.Relationship>();                
            }
            MyObjects.Relationship rel = new MyObjects.Relationship();
            rel.ToObjectId = objId;
            rel.ToObjectCode = objCode;
            rel.ToObjectName = objName;
            rel.ToObjectType = objType;
            Relationships.Add(rel); 
            return rel;
        }
    }

    public class CustomValue {
        public string Code { get; set;}
        public string Value { get; set;}
    }

    public class Relationship {
        public string ToObjectType {get; set;}
        public string ToObjectId {get; set;}
        public string ToObjectName {get; set;}
        public string ToObjectCode {get; set;}
        public string ToObjectIs {get; set;}
        public string ToObjectSource {get; set;}
        public string Status {get; set;}
        public decimal Quantity {get; set;}
        public DateTime StartDate {get; set;}
        public DateTime EndDate {get; set;}
        public List<CustomValue> CustomValues;
    }

    public abstract class MoneyTransfer extends MyBase {
        public decimal Amount { get; set;}
        public decimal EffectiveDate { get; set;}
        public TransactionCurrency TransactionCurrency { get; set;}
    }

    public class Language extends MyBase {
    }

    public class TransactionCurrency extends MyBase {
    }

    public class Country extends MyBase {
    }

    public class StateOrProvince extends MyBase {
    }

    public class MyAddress extends MyBase {
        public string Street { get; set;}
        public string City { get; set;}
        public Country Country { get; set;}
        public StateOrProvince StateOrProvince { get; set;}
    }

    public class MyOrder extends MyBase {
        public decimal TotalPrice { get; set;}
        public date OrderDate { get; set;}//??
        public TransactionCurrency TransactionCurrency { get; set;}
        public List<MyOrderLine> OrderLines;
    }

    public class MyInvoice extends MyBase {
        public decimal TotalPrice { get; set;}
        public date InvoiceDate { get; set;}
        public TransactionCurrency TransactionCurrency { get; set;}
        public List<InvoiceLine> InvoiceLines;
    }

    public class MyOrderLine extends MyBase {
        public decimal UnitPrice { get; set;}
        public decimal Quantity { get; set;}
        public TaxRate Tax { get; set;}
        public MyProduct Product { get; set;}
    }

    public class InvoiceLine extends MyBase {
        public decimal UnitPrice { get; set;}
        public decimal Quantity { get; set;}
        public TaxRate Tax { get; set;}
        public MyProduct Product { get; set;}
    }

    public class TaxRate extends MyBase {
        public decimal Percentage { get; set;}
        public decimal Amount { get; set;}
    }

    public class MyProduct extends MyBase {
    }

    public class Payment extends MoneyTransfer {
    }

    public class Refund extends MoneyTransfer {
    }
    public class MyAccount extends MyBase {
        public string TaxId { get; set;}
        public string AccountType { get; set;}
        public List<MyContact> Contacts;
        public List<MyAddress> Addresses;
    }

    public class MyContact extends MyBase {
        public string FirstName { get; set;}
        public string LastName { get; set;}
    }

}

Serialize
MyObjects pObjects = new MyObjects(); 

 MyObjects.Country Country = new MyObjects.Country();
 MyObjects.StateOrProvince sop = new MyObjects.StateOrProvince();

 List<MyObjects.MyAddress> MyAdr = new List<MyObjects.MyAddress>();
 MyObjects.MyAddress pa = new MyObjects.MyAddress();
 pa.status = 'status';
 pa.street = 'street';
 pa.City = 'City';
 pa.Name = 'Name';
 pa.ModifiedDate = system.Date.today();
 pa.CreatedDate = system.Date.today();
 pa.Code = 'code123456';
 pa.Id = 'id123445667';
 pa.Country = Country;
 pa.StateOrProvince = sop;
 MyAdr.add(pa);
 pobjects.accounts = new List<MyObjects.MyAccount>();
 MyObjects.MyAccount MyAccount = new MyObjects.MyAccount();
 MyAccount.id = 'ID12345';
 MyAccount.Code = 'Code12345';
 MyAccount.TaxId = '12345';
 MyAccount.AccountType = 'AT12345';
 MyAccount.Addresses = MyAdr;
 pobjects.accounts.add(MyAccount);

 pobjects.Contacts = new List<MyObjects.MyContact>();
 MyObjects.MyContact MyCont = new MyObjects.MyContact();
 MyCont.FirstName = 'MyFirstname';
 MyCont.LastName = 'MyLastname';
 MyCont.Status = 'MyStatus';
 pobjects.Contacts.add(MyCont);

 pobjects.Payments = new List<MyObjects.Payment>();
 MyObjects.Payment Payment = new MyObjects.Payment();
 pobjects.Payments.add(Payment);

 pobjects.Refunds = new List<MyObjects.Refund>();
 MyObjects.Refund MyRef = new MyObjects.Refund();
 pobjects.Refunds.add(MyRef);

 pobjects.Orders = new List<MyObjects.MyOrder>();
 MyObjects.MyOrder MyOrd = new MyObjects.MyOrder();
 MyOrd.TotalPrice = 1.00;
 MyOrd.OrderDate = system.Date.today();
 //MyOrd.TransactionCurrency = 1.00;
 //??
 pobjects.Orders.add(MyOrd);

 pobjects.Invoices = new List<MyObjects.MyInvoice>();
 MyObjects.MyInvoice MyInv = new MyObjects.MyInvoice();
 MyOrd.TotalPrice = 1.00;
 MyOrd.OrderDate = system.Date.today();
 pobjects.Invoices.add(MyInv);
 String MyObject = JSON.serialize(pObjects,false);
 system.debug('MyObject: '+ MyObject);

Debug 
    {
  "Refunds": [
    {
      "Status": null,
      "Relationships": null,
      "Name": null,
      "ModifiedDate": null,
      "Id": null,
      "CustomValues": null,
      "CreatedDate": null,
      "Code": null,
      "TransactionCurrency": null,
      "EffectiveDate": null,
      "Amount": null
    }
  ],
  "Payments": [
    {
      "Status": null,
      "Relationships": null,
      "Name": null,
      "ModifiedDate": null,
      "Id": null,
      "CustomValues": null,
      "CreatedDate": null,
      "Code": null,
      "TransactionCurrency": null,
      "EffectiveDate": null,
      "Amount": null
    }
  ],
  "Orders": [
    {
      "Status": null,
      "Relationships": null,
      "Name": null,
      "ModifiedDate": null,
      "Id": null,
      "CustomValues": null,
      "CreatedDate": null,
      "Code": null,
      "TransactionCurrency": null,
      "TotalPrice": 1,
      "OrderLines": null,
      "OrderDate": "2019-04-04"
    }
  ],
  "Invoices": [
    {
      "Status": null,
      "Relationships": null,
      "Name": null,
      "ModifiedDate": null,
      "Id": null,
      "CustomValues": null,
      "CreatedDate": null,
      "Code": null,
      "TransactionCurrency": null,
      "TotalPrice": null,
      "InvoiceLines": null,
      "InvoiceDate": null
    }
  ],
  "Contacts": [
    {
      "Status": "PgwStatus",
      "Relationships": null,
      "Name": null,
      "ModifiedDate": null,
      "Id": null,
      "CustomValues": null,
      "CreatedDate": null,
      "Code": null,
      "LastName": "PgwLastname",
      "FirstName": "PgwFirstname"
    }
  ],
  "Accounts": [
    {
      "Status": null,
      "Relationships": null,
      "Name": null,
      "ModifiedDate": null,
      "Id": "ID12345",
      "CustomValues": null,
      "CreatedDate": null,
      "Code": "Code12345",
      "TaxId": "12345",
      "Contacts": null,
      "Addresses": [
        {
          "Status": null,
          "Relationships": null,
          "Name": null,
          "ModifiedDate": "2019-04-04T00:00:00.000Z",
          "Id": "id123445667",
          "CustomValues": null,
          "CreatedDate": "2019-04-04T00:00:00.000Z",
          "Code": "code123456",
          "Street": "street",
          "StateOrProvince": {
            "Status": null,
            "Relationships": null,
            "Name": null,
            "ModifiedDate": null,
            "Id": null,
            "CustomValues": null,
            "CreatedDate": null,
            "Code": null
          },
          "Country": {
            "Status": null,
            "Relationships": null,
            "Name": null,
            "ModifiedDate": null,
            "Id": null,
            "CustomValues": null,
            "CreatedDate": null,
            "Code": null
          },
          "City": "City"
        }
      ],
      "AccountType": "AT12345"
    }
  ]
}


A: You call JSON.serialize(...) once on the top-level object (pObjects in your case). You make the call when your top-level object contains all other "stuff" you want to be serialized - nested objects, fields, constants, etc. 
This is correct:
pobjects.Invoices.add(MyInv);
String MyObject = JSON.serialize(pObjects,false);

Remove all other calls to JSON.serialize(...), they're not needed.
