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);
3
  • 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, 2016 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, 2016 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, 2016 at 1:18

1 Answer 1

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) { }
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .