I have a job that calls a web service using Spring-WS. I call the service in the first step and get back an org.springframework.ws.soap.SoapMessage that I'd like to put into the ExecutionContext for subsequent steps to play with -- to do things like read the SOAP header and body and extract the message attachments, writing some things to a database and some things to disk.

Unfortunately, SoapMessage and the implementation I'm currently using -- SaajSoapMessage; might switch to AxiomSoapMessage though -- are not Serializable, so Spring Batch throws an exception when I try to put() the SoapMessage in the ExecutionContext, because it can't serialize the object. I thought maybe I could wrap the SoapMessage in another object that has the message as a transient member and implements writeObject(ObjectOutputStream) to convert the SoapMessage to a byte[] member which can be serialized. I think I have code that could do that below. Deserializing the byte[] back into the SoapMessage inside readObject(ObjectInputStream) looks like it's going to be a pain in the butt, though.

I'm wondering if I'm going about this all wrong. (I *am* new to Spring Batch.) Can someone suggest a better way of sharing a SoapMessage -- or any non-Serializable objects for that matter -- among steps in a job?

Or if someone has a better way to serialize/deserialize a SoapMessage, please let me know. I may post something similar in the Spring-WS forum. Here's my code currently, which obviously still needs some getters/setters and a constructor:

Code:
public class SerializableSoapMessage implements Serializable {
  private static final long serialVersionUID = -6443726973648223066L;
  private static final String AXIOM = "axiom";
  private static final String SAAJ = "saaj";

  private transient SoapMessage soapMessage;  // Won't try to serialize this automatically.
  private byte[] soapMessageBytes;            // Raw byte representation of the soap message.
  private String type;                        // Stores which type of Spring SoapMessage implementation we are using.
  
  private void writeObject(ObjectOutputStream out) throws IOException {
    // Convert the unserializable SoapMessage into a field that can be serialized.
    if (soapMessage instanceof SaajSoapMessage) {
      type = SAAJ;
      SaajSoapMessage saajMessage = (SaajSoapMessage) soapMessage;
      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
      try {
        saajMessage.getSaajMessage().writeTo(byteOut);
        soapMessageBytes = byteOut.toByteArray();
      } catch (SOAPException e) {
        throw new IOException("Couldn't write SAAJ SOAP message to byte array because of SOAPException: "+e.getMessage());
      }
    } else if (soapMessage instanceof AxiomSoapMessage) {
      type = AXIOM;
      AxiomSoapMessage axiomMessage = (AxiomSoapMessage) soapMessage;
      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
      try {
        axiomMessage.getAxiomMessage().serialize(byteOut);
        soapMessageBytes = byteOut.toByteArray();
      } catch (XMLStreamException e) {
        throw new IOException("Couldn't write Axiom SOAP message to byte array because of SOAPException: "+e.getMessage());
      }
    } else {
      throw new RuntimeException("Unexpected soap message instance type.");
    }
    out.defaultWriteObject(); // Now serialize normally.
  }
  
  private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();  // Deserialize normally.
    // Now reconstruct the SoapMessage.
    if (type.equals(SAAJ)) {
      // Not sure what to do here.
      // SOAPMessage saajMessage = 
    } else if (type.equals(AXIOM)) {
      // Not sure what to do here.
    } else {
      throw new RuntimeException("Unexpected type value for soap message.");
    }
  }
  
}