[SalesForce] pass an HttpRequest object to a Class that implements the Queueable interface

This is similar to this question, but I'm wondering about the object I'm sending into the Queueable Class.

Here's the Queuable Class (not much more than debug statements at this point)

public class CalloutLogger implements Queueable{
  public transient HttpRequest req;

  public CalloutLogger(httpRequest request){
    system.debug('Queueable Class Constructor invoked....');
    system.debug('Constructor Input "request": ' + request.toString());
    req = request;
    system.debug('Instance Var "req": ' + req.toString());
  }
  public void execute(QueueableContext context){
    system.debug('CalloutLogger.execute invoked...');
    system.debug('httpRequest.toString() : ' + req.toString());
  } 
}

Here's a demo Class that enqueues the job

public class DemoCallout {
    public void simulatedCallout(){
    //setup HttpRequest
    HttpRequest req = new HttpRequest();
    req.setEndpoint('http://www.notarealendpoint.com/service');
    req.setMethod('GET');
    //Examine operations....
    system.debug('HttpRequest.toString() : ' + req.toString());
    CalloutLogger logger = new CalloutLogger(req);
    system.debug('logger var: ' + logger.req);
    ID jobID = System.enqueueJob(logger);
    system.debug('Enqueued Job with Id: ' + jobID);
  }
}

And here's a bit of anonymous Apex that kicks it all off..

DemoCallout demo = new DemoCallout();
demo.simulatedCallout();

The anonymous Apex is successful with a debug log like this…
enter image description here

But the debug log for the Queuable Class give a null reference error for the HttpRequest object variable "req"…

enter image description here

Any suggestions? Is it even possible to pass an HttpRequest object to a Queuable Class (I'm going to want to pass the HttpResponse in too eventually!)

Best Answer

Remove the transient keyword. It causes the variable not to get serialized.

Using the transient Keyword

Use the transient keyword to declare instance variables that can't be saved, and shouldn't be transmitted as part of the view state for a Visualforce page. For example:

Transient Integer currentTotal;

You can also use the transient keyword in Apex classes that are serializable, namely in controllers, controller extensions, or classes that implement the Batchable or Schedulable interface. In addition, you can use transient in classes that define the types of fields declared in the serializable classes.

Problem is...you can't serialize the request and response classes. You might find something like the below helpful:

Serializable Request

public class GenericRequest
{
    String requestType;
    String requestMethod;
    String requestURI;
    String requestParams;
    String requestHeaders;
    String requestBody;
    public GenericRequest(RestRequest request)
    {
        this.requestType = 'Inbound';
        this.requestMethod = request.httpMethod;
        this.requestURI = request.requestURI;
        this.requestParams = (request.params != null) ? JSON.serialize(request.params) : null;
        this.requestHeaders = (request.headers != null) ? JSON.serialize(request.headers) : null;
        this.requestBody = (request.requestBody != null) ? request.requestBody.toString() : null;
    }
    public GenericRequest(HttpRequest request)
    {
        this.requestMethod = request.getMethod();
        this.requestURI = request.getEndpoint();
        this.requestBody = request.getBody();
        this.requestType = 'Outbound';
    }
}

Serializable Response

public class GenericResponse
{
    String responseBody;
    Integer responseStatus;
    public GenericResponse(RestResponse response)
    {
        if (response == null) return;
        responseStatus = response.statusCode;
        if (response.responseBody != null)
            responseBody = response.responseBody.toString();
    }
    public GenericResponse(HttpResponse response)
    {
        if (response == null) return;
        responseStatus = response.getStatusCode();
        responseBody = response.getBody();
    }
}

Queueable Constructor

final GenericRequest request;
public MyQueueable(HttpRequest input)
{
    request = new GenericRequest(input);
}