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."); } } }


Reply With Quote