1

When i run my batch apex latitude and longitude are not getting updated in customer object. i need to update 50000 record.. getting lat and long using google API i able to request 2500 record per IP. even though 2500 record not get updated. but when i ping Endpoint URL manually getting JSON response containing lat and long. kindly any one help me out on this issue. "http://maps.googleapis.com/maps/api/geocode/json?address=Slupsk+poland+76-251+&sensor=false%27" Here is my Batch apex code:

global class batchAccountGeofieldUpdate implements Database.Batchable < sObject > , Database.AllowsCallouts, Database.Stateful {
 global Database.QueryLocator start(Database.BatchableContext BC) {
  //query on Task
  String query = 'SELECT id,BillingStreet,BillingAddress,BillingCity,BillingCountry,BillingPostalCode,BillingState,geoLocation__Longitude__s,geoLocation__Latitude__s   FROM Account where geoLocation__Latitude__s = null and geoLocation__Latitude__s';
  return Database.getQueryLocator(query);
 }

 global void execute(Database.BatchableContext BC, List < Account > Accountupdate) {
  List < Account > modifiedAccounts = new list < Account > ();
  for (Account a: Accountupdate) {
   String address = '';
   if (a.BillingStreet != null)
    address += a.BillingStreet + ', ';
   if (a.BillingCity != null)
    address += a.BillingCity + ', ';
   if (a.BillingState != null)
    address += a.BillingState + ' ';
   if (a.BillingPostalCode != null)
    address += a.BillingPostalCode + ', ';
   if (a.BillingCountry != null)
    address += a.BillingCountry;
   address = EncodingUtil.urlEncode(address, 'UTF-8');

   Http h = new Http();
   HttpRequest req = new HttpRequest();
   if (address != null)

    req.setEndpoint('http://maps.googleapis.com/maps/api/geocode/json?address=' + address + '&sensor=false');
   req.setMethod('GET');
   req.setTimeout(60000);

   try {
    HttpResponse res = h.send(req);
    // parse coordinates from response
    system.debug('Response' + Res);
    JSONParser parser = JSON.createParser(res.getBody());
    double lat = null;
    double lon = null;
    while (parser.nextToken() != null) {
     if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
      (parser.getText() == 'location')) {
      parser.nextToken(); // object start
      while (parser.nextToken() != JSONToken.END_OBJECT) {
       String txt = parser.getText();
       parser.nextToken();
       if (txt == 'lat') {
        lat = parser.getDoubleValue();
        system.debug('++++lat +++++' + lat);
       } else if (txt == 'lng') {
        lon = parser.getDoubleValue();
        system.debug('++++lon+++++' + lon);
       }
      }
     }
    }
    // update coordinates if we get back
    if (lat != null) {
     a.geoLocation__Latitude__s = lat;
     a.geoLocation__Longitude__s = lon;
     modifiedAccounts.add(a);
     system.debug('++++a.BillingLatitude+++++' + a.geoLocation__Latitude__s + '====' + a.geoLocation__Longitude__s);
    }
   } catch (Exception e) {}
  }

  update modifiedAccounts;
 }

 global void finish(Database.BatchableContext BC) { }
}

Code to execute:

batchAccountGeofieldUpdate  Accountbatch = new  batchAccountGeofieldUpdate();
Database.executeBatch(Accountbatch,50);
  • 1
    I am not able to see the code where you are signing your request. You need to sign your request before sending it to Google Maps API. – abhi Feb 2 '16 at 15:35
  • I suspect you're hitting the "You have uncommitted work pending. Please commit or rollback before calling out" error if you look in your logs. – abhi Feb 2 '16 at 22:04
  • geez, if I recall, the appleman advanced apex 3rd edition uses this problem as motivation for his scalable async apex patterm – cropredy Feb 3 '16 at 1:18
1

If you're facing the issue of unable to make callouts from a batch, I suggest the following change in your code. Firstly I have found it easy to have a JSON class that can be used to serialize / deserialize using native methods.

public class google {

    public class Address_components {
        public String long_name;
        public String short_name;
        public List<String> types;
    }

    public class Geometry {
        public Bounds bounds;
        public Northeast location;
        public String location_type;
        public Bounds viewport;
    }

    public List<Results> results;
    public String status;

    public class Results {
        public List<Address_components> address_components;
        public String formatted_address;
        public Geometry geometry;
        public String place_id;
        public List<String> types;
    }

    public class Bounds {
        public Northeast northeast;
        public Northeast southwest;
    }

    public class Northeast {
        public Double lat;
        public Double lng;
    }


    public static google parse(String json) {
        return (google) System.JSON.deserialize(json, google.class);
    }
}

Next you will need to put the webservice call method outside. I have tried this with 20 accounts and it is working for me in my developer org.

    global class batchAccountGeofieldUpdate implements Database.Batchable <sObject> , Database.AllowsCallouts, Database.Stateful 
{
 global Database.QueryLocator start(Database.BatchableContext BC) 
 {
  //query on Task
  String query = 'SELECT id,BillingStreet,BillingAddress,BillingCity,BillingCountry,BillingPostalCode,BillingState, GeoCoords__latitude__s, GeoCoords__longitude__s FROM Account where GeoCoords__latitude__s = NULL';
  return Database.getQueryLocator(query);
 }

 global void execute(Database.BatchableContext BC, List <Account> Accountupdate) 
 {
  List < Account > modifiedAccounts = new list <Account> ();
  for (Account a: Accountupdate) 
  {
   String address = '';
   if (a.BillingStreet != null)
    address += a.BillingStreet + ', ';
   if (a.BillingCity != null)
    address += a.BillingCity + ', ';
   if (a.BillingState != null)
    address += a.BillingState + ' ';
   if (a.BillingPostalCode != null)
    address += a.BillingPostalCode + ', ';
   if (a.BillingCountry != null)
    address += a.BillingCountry;
   address = EncodingUtil.urlEncode(address, 'UTF-8');

   try{
        google gro = callGoogleApex(address);
        System.Debug(gro.results.size());
        if(gro.results.size() > 0)
        {
            double lat = gro.results[0].geometry.location.lat;
            double lon = gro.results[0].geometry.location.lng;

            if (lat != null) 
            {
             system.debug('lat is not null');
             a.GeoCoords__latitude__s = lat;
             a.GeoCoords__longitude__s = lon;
             modifiedAccounts.add(a);
             system.debug('++++a.BillingLatitude+++++' +          a.GeoCoords__latitude__s );
            }
        }
        else
        {
            System.Debug('nothing in list. what am i going to do?');
        }
      } 
   catch (Exception e) {}
  update modifiedAccounts;
  }
  }



public static google callGoogleApex(string address)
{
   Http h = new Http();
   HttpRequest req = new HttpRequest();
   google gro = new google();
   if (address != null)
   {
    req.setEndpoint('http://maps.googleapis.com/maps/api/geocode/json?address=' + address + '&sensor=false');
    req.setMethod('GET');
    req.setTimeout(6000);

        HttpResponse res = h.send(req);
        JSONParser parser = JSON.createParser(res.getBody());
        while(parser.nextToken() != null)
        {
            if(parser.getCurrentToken()==JSONToken.START_OBJECT){
                gro = (google) parser.readValueAs(MySampleApp.google.class);
            }    
        }    
     }
        return gro;

}
global void finish(Database.BatchableContext BC) { }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.