function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Ivan WinzerIvan Winzer 

Can not write a field name, expecting a value

So been working with my buddy Greg C and have code that sends data to third party system thru Json Post calls. When creating a new record in salesforce the class fires correctly and it passes over with no issue. Currently working on trigger to push address entries to push over as well. Now when i try to edit a contact record with no address related record the class fires off no issues but soon as you add a address record and try to edit a contacat i get the "System.JSONException: Can not write a field name, expecting a value" error message for the following line:

Class.MagentoUtility.getAddresses: line 78, column 1
Class.MagentoUtility.magentoPost: line 118, column 1

Here is the class that i am using and the trigger which im not sure how to get this to pass over without the message.

Class:
global class MagentoUtility {

    //This is a future method used to call the methods we need to get a token and then post to Magento.
    //Since this is executed using a trigger, callouts need to be future methods. As a result, our methods need to be static.
    @future(callout=true)
    public static void magentoIntegration(String contactData){

        String token = getToken();
        magentoPost(token, contactData);

   }
    public static String getToken() {

        //Retrieve Username from Magento Setting (custom metadata type)
        String magentoUsername = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'magentoUsername' LIMIT 1].Value__c;

        //Retrieve Password from Magento Setting (custom metadata type)
        String magentoPassword = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'magentoPassword' LIMIT 1].Value__c;

        //Retrieve Token Enpoint from Magento Setting (custom metadata type)
        String tokenEndpoint = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'tokenEndpoint' LIMIT 1].Value__c;

          //String UserName = 'username';

        /////Retrieve token/////
        HttpRequest req = new HttpRequest();
        req.setEndpoint(tokenEndpoint);
        req.setMethod('POST');

        JSONGenerator gen = JSON.createGenerator(true);
        gen.writeStartObject();
        gen.writeStringField('username', magentoUsername);
        gen.writeStringField('password',magentoPassword);
        gen.writeEndObject();
        String jsonA = gen.getAsString();
        System.debug('jsonMaterials'+jsonA);
        //Specify the required username and password to access the endpoint
           //String authBody = jsonA;
        //'{"username":"' + magentoUsername + '", "password" : "' + magentoPassword + '" }';
           //String parseJson = System.debug(Json.serialize(authBody));
        req.setBody(jsonA);
        req.setHeader('Content-Type', 'application/json; charset=UTF-8');

        Http http = new Http();
        HTTPResponse res = http.send(req);
        //JSONParser parser = JSON.createParser(res.getBody());
        System.debug('Response: ' + res.getBody());

        String authToken = res.getBody();
        authToken = authToken.replace('\\', '');
        authToken = authToken.replace('"', '');
        //String authToken = json.Replace("\", "");

        return authToken;
          //return authToken;
           //String parseJson = Json.serialize(authToken);
           //return parseJson;
    }

    public static Map<Id,String> getAddresses(List<Contact> contactList) {
        List<Contact> data = new List<Contact>();
        data = [Select Id,(Select Id, FirstName__c, LastName__c, Country__c, Zip__c, State__c, Phone_Number__c, Primary_Billing_Address__c, Default_Shipping_Address__c, Address__c, Address2__c, UUID__c  From R00N40000001gQKfEAM) From Contact c WHERE (c.Id IN (SELECT Contact__c FROM ShipTo_Address__c)) AND ( c.Id IN :contactList)];
        //data = [Select Id,(Select Id From ShipTo_Addresses__r) From Contact c WHERE (c.Id IN (SELECT Contact__c FROM ShipTo_Address__c)) AND ( c.Id IN :contactList)];
        
        Map<Id, String> contactAddressMap = new Map<Id, String>();

        for(Contact c : data){
            //Create JSON Generator for creating JSON Array for addresses
            JSONGenerator gen = JSON.createGenerator(true);

            for(ShipTo_Address__c cd : c.R00N40000001gQKfEAM){
            //for(ShipTo_Address__c cd : c.ShipTo_Addresses__r){
                //Build address data for each Contact passed by trigger
               //gen.writeStartObject();
               //gen.writeFieldName('addresses');
                gen.writeStartArray();
                if (cd.FirstName__c != Null){
                gen.writeStringField('firstname', cd.FirstName__c);
                } else {
                gen.writeStringField('firstname','');
                }
                gen.writeStringField('lastname', cd.LastName__c);
                gen.writeStringField('countryId', cd.Country__c);
                gen.writeStringField('postalcode', cd.ZIP__c);
                gen.writeStringField('state', cd.State__c);
                gen.writeStringField('telephone', cd.Phone_Number__c);
                gen.writeBooleanField('defaultBilling', cd.Primary_Billing_Address__c);
                gen.writeBooleanField('defaultShipping', cd.Default_Shipping_Address__c);
                if ( cd.Address2__c != null ){
                    gen.writeStringField('street', cd.Address__c + ' ' + cd.Address2__c);
                } else {
                    gen.writeStringField('street', cd.Address__c); 
                }
                //To avoid null pointer exception
                if( cd.UUID__c != null ) {
                    gen.writeStringField('uuid', cd.UUID__c); 
                }
                //gen.writeEndObject();
                gen.writeEndArray();
                gen.close();
            }

            //Add the child address to the map of the parent Contact ID and the address data
            contactAddressMap.put(c.Id, gen.getAsString());
        }
        return contactAddressMap;
    }

    public static void magentoPost(String token, String contactData) {
        //Retrieve Token Endpoint from Magento Setting (custom metadata type)
        String syncEndpoint = [SELECT Value__c FROM Magento_Setting__mdt WHERE DeveloperName = 'syncEndpoint' LIMIT 1].Value__c;

        //Deserialize the JSON string passed by the Contact trigger. We have to pass this as JSON because future methods don't support passing sObjects.
        List<Contact> contactList = (List<Contact>) Json.deserialize(contactData, List<Contact>.class);

        //Obtain the address data from child object
        Map<Id, String> addressMap = new Map<Id, String>();
        addressMap = getAddresses(contactList);

        //Loop through the new Contacts
        for( Contact c : contactList ) {
            HttpRequest req = new HttpRequest();
            req.setEndpoint(syncEndpoint);
            req.setMethod('POST');
            req.setHeader('Content-Type', 'application/json; charset=UTF-8');
            req.setHeader('Authorization', 'Bearer ' + token);

            JSONGenerator gen = JSON.createGenerator(true);

            //We need to create { "customer": {
            //writeStartObject() - Writes the starting marker of a JSON object ('{').
            gen.writeStartObject();
            gen.writeFieldName('customer');
            gen.writeStartObject();

            gen.writeStringField('firstname',c.FirstName);
            gen.writeStringField('lastname',c.LastName);
            gen.writeStringField('email',c.Email);
            gen.writeStringField('telephone',c.HomePhone);
            gen.writeStringField('contact_sf_id',c.Id);
            gen.writeDateTimeField('sfdc_updated_at',c.LastModifiedDate);
            if( c.Account.RMS_Account_Number__c != null ){
                gen.writeStringField('rms_account_no', c.Account.RMS_Account_Number__c);
            }
            gen.writeStringField('customer_group_code',c.Pricing_Profile__c);
            if( c.Revel_Id__c != null ) {
                gen.writeStringField('revel_id', c.Revel_Id__c);
            }
            //To avoid null pointer exception
            if( c.Magento_Associate_to_Website__c != null ) {
                gen.writeStringField('website_id', c.Magento_Associate_to_Website__c); 
            }
            //To avoid null pointer exception
            if( c.Store_ID__c != null ) {
                gen.writeStringField('store_id', c.Store_ID__c); 
            }
            //To avoid null pointer exception
            if( c.UUID__c != null ) {
                gen.writeStringField('uuid', c.UUID__c); 
            }

            //Addresses is a JSON array, so we use writeObjectField method based upon example in Salesforce documentation
            //Line 47 in their example code - https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_json_jsongenerator.htm
            if( addressMap.get(c.Id) != null ) {
                gen.writeObjectField('addresses', addressMap.get(c.Id));
            }

            //Expected JSON data ends in '} }' so we call "writeEndObject" twice
            gen.writeEndObject();
            gen.writeEndObject();

            String jsonStr = gen.getAsString();
            System.debug('JSON String: ' + jsonStr);

            req.setBody(jsonStr);

            System.debug('Req Body: ' + req.getBody());
            System.debug('Req Body as Blob: ' + req.getBodyAsBlob());

            Http http = new Http();
            HTTPResponse res = http.send(req);
            System.debug('Response Body: ' + res.getBody());
            System.debug('Response Body as Blob: ' + res.getBodyAsBlob());
        }
    }
}

Trigger:
trigger MainContactTrigger on Contact (before update, before insert, after update, after insert) {
    DuplicateEmailFilter def = new DuplicateEmailFilter();
    Map<id,Contact> oldMap = trigger.oldMap;
    CreateAccountFromContact accountCreation = New CreateAccountFromContact();
    
    if(oldMap == null){
        oldMap = new Map<Id,Contact>();
    }
    if(Trigger.isBefore){
    // 
    // For the before creation we check if the contact is getting created by a real user then we use 
    // the Duplicate Email Filter to generate an error preventing the contact from being created.
    
        if(!IntegrationUtils.isIntegrationUser()){
            def.processContacts(trigger.new, oldMap);
        }
        if( Trigger.isInsert && !IntegrationUtils.ignoreForAutoAccountUser() ) {
            accountCreation.ProcessBatchContactsWEmail(trigger.new,trigger.oldMap);
        }
        else if( Trigger.isInsert || Trigger.isUpdate ) {
            accountCreation.ProcessBatchContacts(trigger.new,trigger.oldMap);
        }
    }
    else if(Trigger.isAfter){
    //
    // This is the After trigger - we just need to check if the email address is already
    // in use in the duplicate email filter. 
    // if it is being created by the integration user then in the DEF we flag the contact as having 
    // a duplicate. Leaving it up to the Salesforce Admin to clean it up.
    //
        if(IntegrationUtils.isIntegrationUser()){
            def.processContacts(trigger.new, oldMap);
        }
        
        //Magento Integration
        if( Trigger.isInsert || Trigger.isUpdate  ){
            String jsonString = json.serialize(Trigger.NEW);
            MagentoUtility.magentoIntegration(jsonString);
        }
    }
}

Any input is greatly appreciated.

Ivan