1

I want to create a XML Head in start method of a batch class. I was getting "System.SerializationException: Not Serializable: dom.Document" error for DOM. To handle this I declared all the variables as transient. But now my state is not being maintained between Start and execute method. Below is the code snippet.

global class XMLCreation implements Database.batchable<SObject>, Database.Stateful {
global String xForm;
transient global Dom.Document document;
transient global Dom.Xmlnode xmlRoot;
transient global Dom.Xmlnode xmlHead;
transient global Dom.Xmlnode xmlModel;
transient global Dom.Xmlnode xmlInstance;
transient global Dom.Xmlnode xmlData;

public NonCascadingXformBatch(XYZ__c XYZ) {
    this.XYZ = XYZ;
}

/**
 * Start method
 */
global List<Question__c> start(Database.batchableContext batchableContext) {

    this.document = new Dom.Document();
    this.xmlRoot = this.document.createRootElement('h:html', null, null);

    this.xmlRoot.setNamespace('jr',<namespace>);
    this.xmlRoot.setNamespace('h', <xtz>);

    // Some query on question object

    this.xmlHead = this.xmlRoot.addChildElement('h:head',null,null);
    this.xmlHead.addChildElement('h:title',null,null).addTextNode(this.surveyVersion.Survey__r.Name);
    this.xmlModel = this.xmlHead.addChildElement('model',null,null);
    this.xmlInstance = this.xmlModel.addChildElement('instance',null,null);
    this.xmlData = this.xmlInstance.addChildElement('data',null,null);
    this.xmlData.setAttribute('id',surveyVersion.Id);
    return questions;
}

/**
 * Execute method
 */
global void execute(Database.BatchableContext BC, List<Question__c> questions) {
    for (Question__c question : questions) {
        setHeaderModel(this.xmlData, question.Name);
    }
} 

In Exceute method "xmlData" is blank.

  • 1
    I realize you used the transient keyword because of the serialization. By using transient variables, you won't be able to maintain state which is the cause of the issue your having. Is there a way to rewrite your code so that it gets saved to another variable for the purpose of state rather than an instance variable once created? Either that or perhaps not all of your variables need to be transient? – crmprogdev Jul 4 '16 at 14:49
  • I need to add transient keyword to all variables for DOM to avoid serialization error. All these variables if not declared as transient give "System.SerializationException: Not Serializable: dom.Document" error. But by transient I can't maintain the state. And if I save to any other varaible also it will be of same type and will need to declare those also transient. – Garima Kour Jul 4 '16 at 14:56
  • 1
    I'm voting to close this question as off-topic because you cannot or will not specify your desired end result. I will consider it on topic if you outline the document you are trying to create. Please use sufficient detail to understand what you are trying to serialize based on the records being processed. Ideally you should show a sample of the desired markup, even if it uses pseudo-code to get the point across. – Adrian Larson Jul 5 '16 at 8:50
  • My issue is not with the approach. My issue was with using a DOM in start method and maintaining state. If this approach has a limitation I can go for the other one and need not mention the details here because that is not required. Thanks a lot for you time again. – Garima Kour Jul 5 '16 at 9:09
  • did you consider managing state yourself ? you could store the data somewhere else in the database than to rely on the standard mechanism. Or .. that is at least what I would try. – Samuel De Rycke Jul 5 '16 at 11:32
1

As you have found, transient does not make your error go away. You just stop tracking that state. It does not make any sense to use transient variables in a Stateful batch.

Is it really state that you need to track between execute calls, though? Based on the code you have shared, it does not seem so. Consider building/manipulating your xml in the execute method itself.

global class XMLCreation implements Database.batchable<SObject>
{
    global Database.queryLocator start(Database.BatchableContext context)
    {
        return Database.getQueryLocator([/*query*/]);
    }
    global void execute(Database.BatchableContext context, List<SObject> questions)
    {
        // Build your XML here
        // Scoping locally will avoid serialization
        Dom.Document document;
        Dom.Xmlnode xmlRoot;
        Dom.Xmlnode xmlHead;
        Dom.Xmlnode xmlModel;
        Dom.Xmlnode xmlInstance;
        Dom.Xmlnode xmlData;

    }
    global void finish(Database.BatchableContext context) { }
}
|improve this answer|||||
  • Thanks for the suggestion. But I really want to build some part of the xml in start method and then continue in execute method. I know using transient with stateful doesn't make sense. This is where I am stuck. If I don't use transient I get "System.SerializationException: Not Serializable: dom.Document" error for DOM variables – Garima Kour Jul 5 '16 at 5:54
  • Please clarify why building this structure (which is not serializable) in the execute method is not an option. Right now it sounds like the answer is simply because you don't want to. You have to acknowledge the reality of the constraints imposed by the system at a certain point. – Adrian Larson Jul 5 '16 at 6:05
  • This is part of my requirement. I want to create XML head part in start method and then body part in execute method.Its not about how I want or not, its about what my scenario requires at the moment. In short my head part will be created for all the records in one go and body requires more processing so need to create that in execute method in batches. – Garima Kour Jul 5 '16 at 6:33
  • Is the entire batch creating one xml document? One per record? – Adrian Larson Jul 5 '16 at 7:02
  • No. We will be doing chaining of batches. My Head part will be done in start method. Then execute part will create body for the records. Then next batch will be called which will form next part of the body for a csv file. – Garima Kour Jul 5 '16 at 7:43

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