6

I am trying to connect to a weather API.

The class was created from wsdl2apex

public class AsyncWeatherRequestWebService2 {
public class GetCitiesByCountryResponse_elementFuture extends System.WebServiceCalloutFuture {
    public String getValue() {
        WeatherRequestWebService2.GetCitiesByCountryResponse_element response = (WeatherRequestWebService2.GetCitiesByCountryResponse_element)System.WebServiceCallout.endInvoke(this);
        return response.GetCitiesByCountryResult;
    }
}
public class GetWeatherResponse_elementFuture extends System.WebServiceCalloutFuture {
    public String getValue() {
        WeatherRequestWebService2.GetWeatherResponse_element response = (WeatherRequestWebService2.GetWeatherResponse_element)System.WebServiceCallout.endInvoke(this);
        return response.GetWeatherResult;
    }
}
public class AsyncGlobalWeatherSoap {
    public String endpoint_x = 'http://www.webservicex.net/globalweather.asmx';
    public Map<String,String> inputHttpHeaders_x;
    public String clientCertName_x;
    public Integer timeout_x;
    private String[] ns_map_type_info = new String[]{'http://www.webserviceX.NET', 'WeatherRequestWebService2'};
    public AsyncWeatherRequestWebService2.GetCitiesByCountryResponse_elementFuture beginGetCitiesByCountry(System.Continuation continuation,String CountryName) {
        WeatherRequestWebService2.GetCitiesByCountry_element request_x = new WeatherRequestWebService2.GetCitiesByCountry_element();
        request_x.CountryName = CountryName;
        return (AsyncWeatherRequestWebService2.GetCitiesByCountryResponse_elementFuture) System.WebServiceCallout.beginInvoke(
          this,
          request_x,
          AsyncWeatherRequestWebService2.GetCitiesByCountryResponse_elementFuture.class,
          continuation,
          new String[]{endpoint_x,
          'http://www.webserviceX.NET/GetCitiesByCountry',
          'http://www.webserviceX.NET',
          'GetCitiesByCountry',
          'http://www.webserviceX.NET',
          'GetCitiesByCountryResponse',
          'WeatherRequestWebService2.GetCitiesByCountryResponse_element'}
        );
    }
    public AsyncWeatherRequestWebService2.GetWeatherResponse_elementFuture beginGetWeather(System.Continuation continuation,String CityName,String CountryName) {
        WeatherRequestWebService2.GetWeather_element request_x = new WeatherRequestWebService2.GetWeather_element();
        request_x.CityName = CityName;
        request_x.CountryName = CountryName;
        return (AsyncWeatherRequestWebService2.GetWeatherResponse_elementFuture) System.WebServiceCallout.beginInvoke(
          this,
          request_x,
          AsyncWeatherRequestWebService2.GetWeatherResponse_elementFuture.class,
          continuation,
          new String[]{endpoint_x,
          'http://www.webserviceX.NET/GetWeather',
          'http://www.webserviceX.NET',
          'GetWeather',
          'http://www.webserviceX.NET',
          'GetWeatherResponse',
          'WeatherRequestWebService2.GetWeatherResponse_element'}
        );
    }
}

}

I am just testing this using the execute anonymous window

AsyncWeatherRequestWebService2.GetWeatherResponse_elementFuture GetWeatherRequestService;

 AsyncWeatherRequestWebService2.AsyncGlobalWeatherSoap GetWeatherRequest = new AsyncWeatherRequestWebService2.AsyncGlobalWeatherSoap();   

 Integer TIMEOUT_INT_SECS = 90;  
 Continuation cont = new Continuation(TIMEOUT_INT_SECS);
 cont.continuationMethod = 'processResponse';     


GetWeatherRequestService = GetWeatherRequest.beginGetWeather(cont, 'Paris','france'); 

GetWeatherRequestService.getValue(); 

and the error i am receiving is System.NullPointerException: Attempt to de-reference a null object pointing to return response.GetWeatherResult;

when i test the webservice using SOAPUI, it does return something.

so is this issue in the way i am calling the webservice? is the generated class missing something?

help please!


It is probably because of the "cont.continuationMethod = 'processResponse'; "

does it require a call back method?

public Object processResponse() {
result = GetWeatherRequestService.getValue();
return result;

5
  • could you please share where can I find a link or process to get the weather API, wsdl – Suresh Apr 28 '15 at 13:52
  • @Suri WSDL but I couldn't get it to import into Salesforce (because of the SOAP 1.2 stuff in there) Muriel, could you please share your WSDL? – bananka Apr 28 '15 at 14:28
  • 1
    Hi, webservicex.net/globalweather.asmx?WSDL – Muriel Apr 28 '15 at 14:58
  • t is probably because of the "cont.continuationMethod = 'processResponse'; " does it require a call back method? public Object processResponse() { result = GetWeatherRequestService.getValue(); return result; – Muriel Apr 28 '15 at 15:06
  • @Muriel : I have a very similar problem. When I try to invoke the class created from WSDL2Apex, it returns null value. I am trying to call it from workbench just like you. I believe you got this working. Can you explain how? I didn't follow the solution mentioned. – Kunal Shah Oct 27 '15 at 20:43
2

Wsdl2Apex now creates two sets of Apex classes for interacting with the SOAP based web service.

  • The first use WebServiceCallout.invoke and are synchronous. These are historically all that were generated.
  • The second use what is called a Continuation. These are new in Spring 15. See Make Long-Running Callouts from a Visualforce Page. It will use WebServiceCallout.beginInvoke and WebServiceCallout.endInvoke calls

For the purposes of testing the web service via anonymous apex you will want to use the former. It will have a name like WeatherRequestWebService2 based on your sample code.

E.g. (After adding Remote Sites setting for http://www.webservicex.net)

wwwWebservicexNet.GlobalWeatherSoap ws = new wwwWebservicexNet.GlobalWeatherSoap();

//System.debug(ws.GetCitiesByCountry('France'));

string weather = ws.GetWeather('Paris / Le Bourget', 'France');
System.debug(weather);

Gives:

<?xml version="1.0" encoding="utf-16"?>
<CurrentWeather>
  <Location>Paris / Le Bourget, France (LFPB) 48-58N 002-27E 65M</Location>
  <Time>Apr 28, 2015 - 07:00 PM EDT / 2015.04.28 2300 UTC</Time>
  <Wind> from the N (010 degrees) at 5 MPH (4 KT):0</Wind>
  <Visibility> greater than 7 mile(s):0</Visibility>
  <Temperature> 42 F (6 C)</Temperature>
  <DewPoint> 35 F (2 C)</DewPoint>
  <RelativeHumidity> 75%</RelativeHumidity>
  <Pressure> 30.15 in. Hg (1021 hPa)</Pressure>
  <Status>Success</Status>
</CurrentWeather>
3
  • thanks Daniel. so can you use a "continuation callout" from a trigger using @future(callout=true)? or would you simply use the synchronous callout from a @future trigger? – Muriel Apr 29 '15 at 8:52
  • You would use the synchronous version from a future context. As far as I've seen Continuations are only used from Visualforce. – Daniel Ballinger Apr 29 '15 at 9:07
  • @Muriel Great. Convention on Stack Exchange sites is to mark an accepted answer with the green check mark that appear by the voting buttons. This will indicate to others that a solution has been found. – Daniel Ballinger Apr 29 '15 at 19:30
1

Yes it requires callback method. You must return Continuation object in controller, let's assume that you have method callWeatherWebService() in controller, looking like this:

public Object callWeatherWebService() {
    Continuation cont = new Continuation(TIMEOUT_INT_SECS);
    cont.continuationMethod = 'processResponse';
    GetWeatherRequestService = GetWeatherRequest.beginGetWeather(cont, 'Paris','france');
    return cont;
}

Then you have to provide callback method, note that result must public field in your controller:

public void processResponse() {
    result = GetWeatherRequestService.getValue();
}

When webservice returns results, callback method is invoked and then your page is refreshed with new value (result).

2
  • @ mischczu: this would work fine from a visualforce page. now if i want to call this from trigger with @Future(callout=true), i am not sure how this is supposed to work. Basically, the trigger calls a global class with a public static void. This public static void is suposed to call the webservice (that bit works ok), but I am having problem with the call back. – Muriel Apr 29 '15 at 8:31
  • OK, so I would use synchronous version from trigger with future, because I don't think that Continuation object is supported in triggers. It requires special handling, which is provided by Controller. Now I've seen that earlier @Daniel Ballinger suggested that :) – mischczu Apr 29 '15 at 9:28

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.